Browse Source

Removed old Blender exporters.

Mr.doob 12 years ago
parent
commit
986eec24aa

+ 0 - 454
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/__init__.py

@@ -1,454 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# ################################################################
-# Init
-# ################################################################
-
-
-bl_info = {
-    "name": "three.js format",
-    "author": "mrdoob, kikko, alteredq, remoe, pxf, n3tfr34k",
-    "version": (1, 4, 0),
-    "blender": (2, 6, 3),
-    "api": 35622,
-    "location": "File > Import-Export",
-    "description": "Import-Export three.js meshes",
-    "warning": "",
-    "wiki_url": "https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender",
-    "tracker_url": "https://github.com/mrdoob/three.js/issues",
-    "category": "Import-Export"}
-
-# To support reload properly, try to access a package var,
-# if it's there, reload everything
-
-import bpy
-
-if "bpy" in locals():
-    import imp
-    if "export_threejs" in locals():
-        imp.reload(export_threejs)
-    if "import_threejs" in locals():
-        imp.reload(import_threejs)
-
-from bpy.props import *
-from bpy_extras.io_utils import ExportHelper, ImportHelper
-
-# ################################################################
-# Custom properties
-# ################################################################
-
-bpy.types.Object.THREE_castShadow = bpy.props.BoolProperty()
-bpy.types.Object.THREE_receiveShadow = bpy.props.BoolProperty()
-bpy.types.Object.THREE_doubleSided = bpy.props.BoolProperty()
-bpy.types.Object.THREE_exportGeometry = bpy.props.BoolProperty(default = True)
-
-bpy.types.Material.THREE_useVertexColors = bpy.props.BoolProperty()
-bpy.types.Material.THREE_depthWrite = bpy.props.BoolProperty(default = True)
-bpy.types.Material.THREE_depthTest = bpy.props.BoolProperty(default = True)
-
-THREE_material_types = [("Basic", "Basic", "Basic"), ("Phong", "Phong", "Phong"), ("Lambert", "Lambert", "Lambert")]
-bpy.types.Material.THREE_materialType = EnumProperty(name = "Material type", description = "Material type", items = THREE_material_types, default = "Lambert")
-
-THREE_blending_types = [("NoBlending", "NoBlending", "NoBlending"), ("NormalBlending", "NormalBlending", "NormalBlending"),
-                        ("AdditiveBlending", "AdditiveBlending", "AdditiveBlending"), ("SubtractiveBlending", "SubtractiveBlending", "SubtractiveBlending"),
-                        ("MultiplyBlending", "MultiplyBlending", "MultiplyBlending"), ("AdditiveAlphaBlending", "AdditiveAlphaBlending", "AdditiveAlphaBlending")]
-bpy.types.Material.THREE_blendingType = EnumProperty(name = "Blending type", description = "Blending type", items = THREE_blending_types, default = "NormalBlending")
-
-class OBJECT_PT_hello( bpy.types.Panel ):
-
-    bl_label = "THREE"
-    bl_space_type = "PROPERTIES"
-    bl_region_type = "WINDOW"
-    bl_context = "object"
-
-    def draw(self, context):
-        layout = self.layout
-        obj = context.object
-
-        row = layout.row()
-        row.label(text="Selected object: " + obj.name )
-
-        row = layout.row()
-        row.prop( obj, "THREE_exportGeometry", text="Export geometry" )
-
-        row = layout.row()
-        row.prop( obj, "THREE_castShadow", text="Casts shadow" )
-
-        row = layout.row()
-        row.prop( obj, "THREE_receiveShadow", text="Receives shadow" )
-
-        row = layout.row()
-        row.prop( obj, "THREE_doubleSided", text="Double sided" )
-
-class MATERIAL_PT_hello( bpy.types.Panel ):
-
-    bl_label = "THREE"
-    bl_space_type = "PROPERTIES"
-    bl_region_type = "WINDOW"
-    bl_context = "material"
-
-    def draw(self, context):
-        layout = self.layout
-        mat = context.material
-
-        row = layout.row()
-        row.label(text="Selected material: " + mat.name )
-
-        row = layout.row()
-        row.prop( mat, "THREE_materialType", text="Material type" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_blendingType", text="Blending type" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_useVertexColors", text="Use vertex colors" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_depthWrite", text="Enable depth writing" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_depthTest", text="Enable depth testing" )
-
-
-# ################################################################
-# Importer
-# ################################################################
-
-class ImportTHREEJS(bpy.types.Operator, ImportHelper):
-    '''Load a Three.js ASCII JSON model'''
-
-    bl_idname = "import.threejs"
-    bl_label = "Import Three.js"
-
-    filename_ext = ".js"
-    filter_glob = StringProperty(default="*.js", options={'HIDDEN'})
-
-    option_flip_yz = BoolProperty(name="Flip YZ", description="Flip YZ", default=True)
-    recalculate_normals = BoolProperty(name="Recalculate normals", description="Recalculate vertex normals", default=True)
-    option_worker = BoolProperty(name="Worker", description="Old format using workers", default=False)
-
-    def execute(self, context):
-        import io_mesh_threejs.import_threejs
-        return io_mesh_threejs.import_threejs.load(self, context, **self.properties)
-
-
-    def draw(self, context):
-        layout = self.layout
-
-        row = layout.row()
-        row.prop(self.properties, "option_flip_yz")
-
-        row = layout.row()
-        row.prop(self.properties, "recalculate_normals")
-
-        row = layout.row()
-        row.prop(self.properties, "option_worker")
-
-
-# ################################################################
-# Exporter - settings
-# ################################################################
-
-SETTINGS_FILE_EXPORT = "threejs_settings_export.js"
-
-import os
-import json
-
-def file_exists(filename):
-    """Return true if file exists and 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_settings_fullpath():
-    return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT)
-
-def save_settings_export(properties):
-
-    settings = {
-    "option_export_scene" : properties.option_export_scene,
-    "option_embed_meshes" : properties.option_embed_meshes,
-    "option_url_base_html" : properties.option_url_base_html,
-    "option_copy_textures" : properties.option_copy_textures,
-
-    "option_lights" : properties.option_lights,
-    "option_cameras" : properties.option_cameras,
-
-    "option_animation_morph" : properties.option_animation_morph,
-    "option_animation_skeletal" : properties.option_animation_skeletal,
-
-    "option_frame_step" : properties.option_frame_step,
-    "option_all_meshes" : properties.option_all_meshes,
-
-    "option_flip_yz"      : properties.option_flip_yz,
-
-    "option_materials"       : properties.option_materials,
-    "option_normals"         : properties.option_normals,
-    "option_colors"          : properties.option_colors,
-    "option_uv_coords"       : properties.option_uv_coords,
-    "option_faces"           : properties.option_faces,
-    "option_vertices"        : properties.option_vertices,
-
-    "option_skinning"        : properties.option_skinning,
-    "option_bones"           : properties.option_bones,
-
-    "option_vertices_truncate" : properties.option_vertices_truncate,
-    "option_scale"        : properties.option_scale,
-
-    "align_model"         : properties.align_model
-    }
-
-    fname = get_settings_fullpath()
-    f = open(fname, "w")
-    json.dump(settings, f)
-
-def restore_settings_export(properties):
-
-    settings = {}
-
-    fname = get_settings_fullpath()
-    if file_exists(fname):
-        f = open(fname, "r")
-        settings = json.load(f)
-
-    properties.option_vertices = settings.get("option_vertices", True)
-    properties.option_vertices_truncate = settings.get("option_vertices_truncate", False)
-    properties.option_faces = settings.get("option_faces", True)
-    properties.option_normals = settings.get("option_normals", True)
-
-    properties.option_colors = settings.get("option_colors", True)
-    properties.option_uv_coords = settings.get("option_uv_coords", True)
-    properties.option_materials = settings.get("option_materials", True)
-
-    properties.option_skinning = settings.get("option_skinning", True)
-    properties.option_bones = settings.get("option_bones", True)
-
-    properties.align_model = settings.get("align_model", "None")
-
-    properties.option_scale = settings.get("option_scale", 1.0)
-    properties.option_flip_yz = settings.get("option_flip_yz", True)
-
-    properties.option_export_scene = settings.get("option_export_scene", False)
-    properties.option_embed_meshes = settings.get("option_embed_meshes", True)
-    properties.option_url_base_html = settings.get("option_url_base_html", False)
-    properties.option_copy_textures = settings.get("option_copy_textures", False)
-
-    properties.option_lights = settings.get("option_lights", False)
-    properties.option_cameras = settings.get("option_cameras", False)
-
-    properties.option_animation_morph = settings.get("option_animation_morph", False)
-    properties.option_animation_skeletal = settings.get("option_animation_skeletal", False)
-
-    properties.option_frame_step = settings.get("option_frame_step", 1)
-    properties.option_all_meshes = settings.get("option_all_meshes", True)
-
-# ################################################################
-# Exporter
-# ################################################################
-
-class ExportTHREEJS(bpy.types.Operator, ExportHelper):
-    '''Export selected object / scene for Three.js (ASCII JSON format).'''
-
-    bl_idname = "export.threejs"
-    bl_label = "Export Three.js"
-
-    filename_ext = ".js"
-
-    option_vertices = BoolProperty(name = "Vertices", description = "Export vertices", default = True)
-    option_vertices_deltas = BoolProperty(name = "Deltas", description = "Delta vertices", default = False)
-    option_vertices_truncate = BoolProperty(name = "Truncate", description = "Truncate vertices", default = False)
-
-    option_faces = BoolProperty(name = "Faces", description = "Export faces", default = True)
-    option_faces_deltas = BoolProperty(name = "Deltas", description = "Delta faces", default = False)
-
-    option_normals = BoolProperty(name = "Normals", description = "Export normals", default = True)
-
-    option_colors = BoolProperty(name = "Colors", description = "Export vertex colors", default = True)
-    option_uv_coords = BoolProperty(name = "UVs", description = "Export texture coordinates", default = True)
-    option_materials = BoolProperty(name = "Materials", description = "Export materials", default = True)
-
-    option_skinning = BoolProperty(name = "Skinning", description = "Export skin data", default = True)
-    option_bones = BoolProperty(name = "Bones", description = "Export bones", default = True)
-
-    align_types = [("None","None","None"), ("Center","Center","Center"), ("Bottom","Bottom","Bottom"), ("Top","Top","Top")]
-    align_model = EnumProperty(name = "Align model", description = "Align model", items = align_types, default = "None")
-
-    option_scale = FloatProperty(name = "Scale", description = "Scale vertices", min = 0.01, max = 1000.0, soft_min = 0.01, soft_max = 1000.0, default = 1.0)
-    option_flip_yz = BoolProperty(name = "Flip YZ", description = "Flip YZ", default = True)
-
-    option_export_scene = BoolProperty(name = "Scene", description = "Export scene", default = False)
-    option_embed_meshes = BoolProperty(name = "Embed meshes", description = "Embed meshes", default = True)
-    option_copy_textures = BoolProperty(name = "Copy textures", description = "Copy textures", default = False)
-    option_url_base_html = BoolProperty(name = "HTML as url base", description = "Use HTML as url base ", default = False)
-
-    option_lights = BoolProperty(name = "Lights", description = "Export default scene lights", default = False)
-    option_cameras = BoolProperty(name = "Cameras", description = "Export default scene cameras", default = False)
-
-    option_animation_morph = BoolProperty(name = "Morph animation", description = "Export animation (morphs)", default = False)
-    option_animation_skeletal = BoolProperty(name = "Skeletal animation", description = "Export animation (skeletal)", default = False)
-
-    option_frame_step = IntProperty(name = "Frame step", description = "Animation frame step", min = 1, max = 1000, soft_min = 1, soft_max = 1000, default = 1)
-    option_all_meshes = BoolProperty(name = "All meshes", description = "All meshes (merged)", default = True)
-
-    def invoke(self, context, event):
-        restore_settings_export(self.properties)
-        return ExportHelper.invoke(self, context, event)
-
-    @classmethod
-    def poll(cls, context):
-        return context.active_object != None
-
-    def execute(self, context):
-        print("Selected: " + context.active_object.name)
-
-        if not self.properties.filepath:
-            raise Exception("filename not set")
-
-        save_settings_export(self.properties)
-
-        filepath = self.filepath
-
-        import io_mesh_threejs.export_threejs
-        return io_mesh_threejs.export_threejs.save(self, context, **self.properties)
-
-    def draw(self, context):
-        layout = self.layout
-
-        row = layout.row()
-        row.label(text="Geometry:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_vertices")
-        # row = layout.row()
-        # row.enabled = self.properties.option_vertices
-        # row.prop(self.properties, "option_vertices_deltas")
-        row.prop(self.properties, "option_vertices_truncate")
-        layout.separator()
-
-        row = layout.row()
-        row.prop(self.properties, "option_faces")
-        row = layout.row()
-        row.enabled = self.properties.option_faces
-        # row.prop(self.properties, "option_faces_deltas")
-        layout.separator()
-
-        row = layout.row()
-        row.prop(self.properties, "option_normals")
-        layout.separator()
-
-        row = layout.row()
-        row.prop(self.properties, "option_bones")
-        row.prop(self.properties, "option_skinning")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Materials:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_uv_coords")
-        row.prop(self.properties, "option_colors")
-        row = layout.row()
-        row.prop(self.properties, "option_materials")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Settings:")
-
-        row = layout.row()
-        row.prop(self.properties, "align_model")
-        row = layout.row()
-        row.prop(self.properties, "option_flip_yz")
-        row.prop(self.properties, "option_scale")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="--------- Experimental ---------")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Scene:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_export_scene")
-        row.prop(self.properties, "option_embed_meshes")
-
-        row = layout.row()
-        row.prop(self.properties, "option_lights")
-        row.prop(self.properties, "option_cameras")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Animation:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_animation_morph")
-        row = layout.row()
-        row.prop(self.properties, "option_animation_skeletal")
-        row = layout.row()
-        row.prop(self.properties, "option_frame_step")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Settings:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_all_meshes")
-
-        row = layout.row()
-        row.prop(self.properties, "option_copy_textures")
-
-        row = layout.row()
-        row.prop(self.properties, "option_url_base_html")
-
-        layout.separator()
-
-
-# ################################################################
-# Common
-# ################################################################
-
-def menu_func_export(self, context):
-    default_path = bpy.data.filepath.replace(".blend", ".js")
-    self.layout.operator(ExportTHREEJS.bl_idname, text="Three.js (.js)").filepath = default_path
-
-def menu_func_import(self, context):
-    self.layout.operator(ImportTHREEJS.bl_idname, text="Three.js (.js)")
-
-def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.INFO_MT_file_export.append(menu_func_export)
-    bpy.types.INFO_MT_file_import.append(menu_func_import)
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    bpy.types.INFO_MT_file_export.remove(menu_func_export)
-    bpy.types.INFO_MT_file_import.remove(menu_func_import)
-
-if __name__ == "__main__":
-    register()

+ 0 - 2380
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -1,2380 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-"""
-Blender exporter for Three.js (ASCII JSON format).
-
-TODO
-    - binary format
-"""
-
-import bpy
-import mathutils
-
-import shutil
-import os
-import os.path
-import math
-import operator
-import random
-
-# #####################################################
-# Configuration
-# #####################################################
-
-DEFAULTS = {
-"bgcolor" : [0, 0, 0],
-"bgalpha" : 1.0,
-
-"position" : [0, 0, 0],
-"rotation" : [-math.pi/2, 0, 0],
-"scale"    : [1, 1, 1],
-
-"camera"  :
-    {
-        "name" : "default_camera",
-        "type" : "perspective",
-        "near" : 1,
-        "far"  : 10000,
-        "fov"  : 60,
-        "aspect": 1.333,
-        "position" : [0, 0, 10],
-        "target"   : [0, 0, 0]
-    },
-
-"light" :
- {
-    "name"       : "default_light",
-    "type"       : "directional",
-    "direction"  : [0, 1, 1],
-    "color"      : [1, 1, 1],
-    "intensity"  : 0.8
- }
-}
-
-# 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]
-
-
-# skinning
-MAX_INFLUENCES = 2
-
-
-# #####################################################
-# Templates - scene
-# #####################################################
-
-TEMPLATE_SCENE_ASCII = """\
-{
-
-"metadata" :
-{
-	"formatVersion" : 3.1,
-	"sourceFile"    : "%(fname)s",
-	"generatedBy"   : "Blender 2.63 Exporter",
-	"objects"       : %(nobjects)s,
-	"geometries"    : %(ngeometries)s,
-	"materials"     : %(nmaterials)s,
-	"textures"      : %(ntextures)s
-},
-
-"type" : "scene",
-"urlBaseType" : %(basetype)s,
-
-%(sections)s
-
-"transform" :
-{
-	"position"  : %(position)s,
-	"rotation"  : %(rotation)s,
-	"scale"     : %(scale)s
-},
-
-"defaults" :
-{
-	"bgcolor" : %(bgcolor)s,
-	"bgalpha" : %(bgalpha)f,
-	"camera"  : %(defcamera)s
-}
-
-}
-"""
-
-TEMPLATE_SECTION = """
-"%s" :
-{
-%s
-},
-"""
-
-TEMPLATE_OBJECT = """\
-	%(object_id)s : {
-		"geometry"  : %(geometry_id)s,
-		"groups"    : [ %(group_id)s ],
-		"materials" : [ %(material_id)s ],
-		"position"  : %(position)s,
-		"rotation"  : %(rotation)s,
-		"quaternion": %(quaternion)s,
-		"scale"     : %(scale)s,
-		"visible"       : %(visible)s,
-		"castShadow"    : %(castShadow)s,
-		"receiveShadow" : %(receiveShadow)s,
-		"doubleSided"   : %(doubleSided)s
-	}"""
-
-TEMPLATE_EMPTY = """\
-	%(object_id)s : {
-		"groups"    : [ %(group_id)s ],
-		"position"  : %(position)s,
-		"rotation"  : %(rotation)s,
-		"quaternion": %(quaternion)s,
-		"scale"     : %(scale)s
-	}"""
-
-TEMPLATE_GEOMETRY_LINK = """\
-	%(geometry_id)s : {
-		"type" : "ascii",
-		"url"  : %(model_file)s
-	}"""
-
-TEMPLATE_GEOMETRY_EMBED = """\
-	%(geometry_id)s : {
-		"type" : "embedded",
-		"id"  : %(embed_id)s
-	}"""
-
-TEMPLATE_TEXTURE = """\
-	%(texture_id)s : {
-		"url": %(texture_file)s%(extras)s
-	}"""
-
-TEMPLATE_MATERIAL_SCENE = """\
-	%(material_id)s : {
-		"type": %(type)s,
-		"parameters": { %(parameters)s }
-	}"""
-
-TEMPLATE_CAMERA_PERSPECTIVE = """\
-	%(camera_id)s : {
-		"type"  : "perspective",
-		"fov"   : %(fov)f,
-		"aspect": %(aspect)f,
-		"near"  : %(near)f,
-		"far"   : %(far)f,
-		"position": %(position)s,
-		"target"  : %(target)s
-	}"""
-
-TEMPLATE_CAMERA_ORTHO = """\
-	%(camera_id)s : {
-		"type"  : "ortho",
-		"left"  : %(left)f,
-		"right" : %(right)f,
-		"top"   : %(top)f,
-		"bottom": %(bottom)f,
-		"near"  : %(near)f,
-		"far"   : %(far)f,
-		"position": %(position)s,
-		"target"  : %(target)s
-	}"""
-
-TEMPLATE_LIGHT_DIRECTIONAL = """\
-	%(light_id)s : {
-		"type"       : "directional",
-		"direction"  : %(direction)s,
-		"color"      : %(color)d,
-		"intensity"  : %(intensity).2f
-	}"""
-
-TEMPLATE_LIGHT_POINT = """\
-	%(light_id)s : {
-		"type"       : "point",
-		"position"   : %(position)s,
-		"color"      : %(color)d,
-		"intensity"  : %(intensity).3f
-	}"""
-
-TEMPLATE_VEC4 = '[ %g, %g, %g, %g ]'
-TEMPLATE_VEC3 = '[ %g, %g, %g ]'
-TEMPLATE_VEC2 = '[ %g, %g ]'
-TEMPLATE_STRING = '"%s"'
-TEMPLATE_HEX = "0x%06x"
-
-# #####################################################
-# Templates - model
-# #####################################################
-
-TEMPLATE_FILE_ASCII = """\
-{
-
-	"metadata" :
-	{
-		"formatVersion" : 3.1,
-		"generatedBy"   : "Blender 2.63 Exporter",
-		"vertices"      : %(nvertex)d,
-		"faces"         : %(nface)d,
-		"normals"       : %(nnormal)d,
-		"colors"        : %(ncolor)d,
-		"uvs"           : [%(nuvs)s],
-		"materials"     : %(nmaterial)d,
-		"morphTargets"  : %(nmorphTarget)d,
-		"bones"         : %(nbone)d
-	},
-
-%(model)s
-
-}
-"""
-
-TEMPLATE_MODEL_ASCII = """\
-	"scale" : %(scale)f,
-
-	"materials" : [%(materials)s],
-
-	"vertices" : [%(vertices)s],
-
-	"morphTargets" : [%(morphTargets)s],
-
-	"normals" : [%(normals)s],
-
-	"colors" : [%(colors)s],
-
-	"uvs" : [%(uvs)s],
-
-	"faces" : [%(faces)s],
-
-	"bones" : [%(bones)s],
-
-	"skinIndices" : [%(indices)s],
-
-	"skinWeights" : [%(weights)s],
-
-	"animation" : {%(animation)s}
-"""
-
-TEMPLATE_VERTEX = "%g,%g,%g"
-TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d"
-
-TEMPLATE_N = "%g,%g,%g"
-TEMPLATE_UV = "%g,%g"
-TEMPLATE_C = "%d"
-
-# #####################################################
-# Utils
-# #####################################################
-
-def veckey3(x,y,z):
-    return round(x, 6), round(y, 6), round(z, 6)
-
-def veckey3d(v):
-    return veckey3(v.x, v.y, v.z)
-
-def veckey2d(v):
-    return round(v[0], 6), round(v[1], 6)
-
-def get_faces(obj):
-    if hasattr(obj, "tessfaces"):
-        return obj.tessfaces
-    else:
-        return obj.faces
-
-def get_normal_indices(v, normals, mesh):
-    n = []
-    mv = mesh.vertices
-
-    for i in v:
-        normal = mv[i].normal
-        key = veckey3d(normal)
-
-        n.append( normals[key] )
-
-    return n
-
-def get_uv_indices(face_index, uvs, mesh, layer_index):
-    uv = []
-    uv_layer = mesh.tessface_uv_textures[layer_index].data
-    for i in uv_layer[face_index].uv:
-        uv.append( uvs[veckey2d(i)] )
-    return uv
-
-def get_color_indices(face_index, colors, mesh):
-    c = []
-    color_layer = mesh.tessface_vertex_colors.active.data
-    face_colors = color_layer[face_index]
-    face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-    for i in face_colors:
-        c.append( colors[hexcolor(i)] )
-    return c
-
-def rgb2int(rgb):
-    color = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255);
-    return color
-
-# #####################################################
-# Utils - files
-# #####################################################
-
-def write_file(fname, content):
-    out = open(fname, "w")
-    out.write(content)
-    out.close()
-
-def ensure_folder_exist(foldername):
-    """Create folder (with whole path) if it doesn't exist yet."""
-
-    if not os.access(foldername, os.R_OK|os.W_OK|os.X_OK):
-        os.makedirs(foldername)
-
-def ensure_extension(filepath, extension):
-    if not filepath.lower().endswith(extension):
-        filepath += extension
-    return filepath
-
-def generate_mesh_filename(meshname, filepath):
-    normpath = os.path.normpath(filepath)
-    path, ext = os.path.splitext(normpath)
-    return "%s.%s%s" % (path, meshname, ext)
-
-
-# #####################################################
-# Utils - alignment
-# #####################################################
-
-def bbox(vertices):
-    """Compute bounding box of vertex array.
-    """
-
-    if len(vertices)>0:
-        minx = maxx = vertices[0].co.x
-        miny = maxy = vertices[0].co.y
-        minz = maxz = vertices[0].co.z
-
-        for v in vertices[1:]:
-            if v.co.x < minx:
-                minx = v.co.x
-            elif v.co.x > maxx:
-                maxx = v.co.x
-
-            if v.co.y < miny:
-                miny = v.co.y
-            elif v.co.y > maxy:
-                maxy = v.co.y
-
-            if v.co.z < minz:
-                minz = v.co.z
-            elif v.co.z > maxz:
-                maxz = v.co.z
-
-        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 range(len(vertices)):
-        vertices[i].co.x += t[0]
-        vertices[i].co.y += t[1]
-        vertices[i].co.z += t[2]
-
-def center(vertices):
-    """Center model (middle of bounding box).
-    """
-
-    bb = bbox(vertices)
-
-    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
-    cy = bb['y'][0] + (bb['y'][1] - bb['y'][0])/2.0
-    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
-
-    translate(vertices, [-cx,-cy,-cz])
-
-def top(vertices):
-    """Align top of the model with the floor (Y-axis) and center it around X and Z.
-    """
-
-    bb = bbox(vertices)
-
-    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
-    cy = bb['y'][1]
-    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
-
-    translate(vertices, [-cx,-cy,-cz])
-
-def bottom(vertices):
-    """Align bottom of the model with the floor (Y-axis) and center it around X and Z.
-    """
-
-    bb = bbox(vertices)
-
-    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
-    cy = bb['y'][0]
-    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
-
-    translate(vertices, [-cx,-cy,-cz])
-
-# #####################################################
-# Elements rendering
-# #####################################################
-
-def hexcolor(c):
-    return ( int(c[0] * 255) << 16  ) + ( int(c[1] * 255) << 8 ) + int(c[2] * 255)
-
-def generate_vertices(vertices, option_vertices_truncate, option_vertices):
-    if not option_vertices:
-        return ""
-
-    return ",".join(generate_vertex(v, option_vertices_truncate) for v in vertices)
-
-def generate_vertex(v, option_vertices_truncate):
-    if not option_vertices_truncate:
-        return TEMPLATE_VERTEX % (v.co.x, v.co.y, v.co.z)
-    else:
-        return TEMPLATE_VERTEX_TRUNCATE % (v.co.x, v.co.y, v.co.z)
-
-def generate_normal(n):
-    return TEMPLATE_N % (n[0], n[1], n[2])
-
-def generate_vertex_color(c):
-    return TEMPLATE_C % c
-
-def generate_uv(uv):
-    return TEMPLATE_UV % (uv[0], uv[1])
-
-# #####################################################
-# Model exporter - faces
-# #####################################################
-
-def setBit(value, position, on):
-    if on:
-        mask = 1 << position
-        return (value | mask)
-    else:
-        mask = ~(1 << position)
-        return (value & mask)
-
-def generate_faces(normals, uv_layers, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces):
-
-    if not option_faces:
-        return "", 0
-
-    vertex_offset = 0
-    material_offset = 0
-
-    chunks = []
-    for mesh, object in meshes:
-
-        vertexUV = len(mesh.uv_textures) > 0
-        vertexColors = len(mesh.vertex_colors) > 0
-
-        mesh_colors = option_colors and vertexColors
-        mesh_uvs = option_uv_coords and vertexUV
-
-        if vertexUV:
-            active_uv_layer = mesh.uv_textures.active
-            if not active_uv_layer:
-                mesh_extract_uvs = False
-
-        if vertexColors:
-            active_col_layer = mesh.vertex_colors.active
-            if not active_col_layer:
-                mesh_extract_colors = False
-
-        for i, f in enumerate(get_faces(mesh)):
-            face = generate_face(f, i, normals, uv_layers, colors, mesh, option_normals, mesh_colors, mesh_uvs, option_materials, vertex_offset, material_offset)
-            chunks.append(face)
-
-        vertex_offset += len(mesh.vertices)
-
-        material_count = len(mesh.materials)
-        if material_count == 0:
-            material_count = 1
-
-        material_offset += material_count
-
-    return ",".join(chunks), len(chunks)
-
-def generate_face(f, faceIndex, normals, uv_layers, colors, mesh, option_normals, option_colors, option_uv_coords, option_materials, vertex_offset, material_offset):
-    isTriangle = ( len(f.vertices) == 3 )
-
-    if isTriangle:
-        nVertices = 3
-    else:
-        nVertices = 4
-
-    hasMaterial = option_materials
-
-    hasFaceUvs = False # not supported in Blender
-    hasFaceVertexUvs = option_uv_coords
-
-    hasFaceNormals = False # don't export any face normals (as they are computed in engine)
-    hasFaceVertexNormals = option_normals
-
-    hasFaceColors = False       # not supported in Blender
-    hasFaceVertexColors = option_colors
-
-    faceType = 0
-    faceType = setBit(faceType, 0, not isTriangle)
-    faceType = setBit(faceType, 1, hasMaterial)
-    faceType = setBit(faceType, 2, hasFaceUvs)
-    faceType = setBit(faceType, 3, hasFaceVertexUvs)
-    faceType = setBit(faceType, 4, hasFaceNormals)
-    faceType = setBit(faceType, 5, hasFaceVertexNormals)
-    faceType = setBit(faceType, 6, hasFaceColors)
-    faceType = setBit(faceType, 7, hasFaceVertexColors)
-
-    faceData = []
-
-    # order is important, must match order in JSONLoader
-
-    # face type
-    # vertex indices
-    # material index
-    # face uvs index
-    # face vertex uvs indices
-    # face color index
-    # face vertex colors indices
-
-    faceData.append(faceType)
-
-    # must clamp in case on polygons bigger than quads
-
-    for i in range(nVertices):
-        index = f.vertices[i] + vertex_offset
-        faceData.append(index)
-
-    if hasMaterial:
-        index = f.material_index + material_offset
-        faceData.append( index )
-
-    if hasFaceVertexUvs:
-        for layer_index, uvs in enumerate(uv_layers):
-            uv = get_uv_indices(faceIndex, uvs, mesh, layer_index)
-            for i in range(nVertices):
-                index = uv[i]
-                faceData.append(index)
-
-    if hasFaceVertexNormals:
-        n = get_normal_indices(f.vertices, normals, mesh)
-        for i in range(nVertices):
-            index = n[i]
-            faceData.append(index)
-
-    if hasFaceVertexColors:
-        c = get_color_indices(faceIndex, colors, mesh)
-        for i in range(nVertices):
-            index = c[i]
-            faceData.append(index)
-
-    return ",".join( map(str, faceData) )
-
-
-# #####################################################
-# Model exporter - normals
-# #####################################################
-
-def extract_vertex_normals(mesh, normals, count):
-    for f in get_faces(mesh):
-        for v in f.vertices:
-
-            normal = mesh.vertices[v].normal
-            key = veckey3d(normal)
-
-            if key not in normals:
-                normals[key] = count
-                count += 1
-
-    return count
-
-def generate_normals(normals, option_normals):
-    if not option_normals:
-        return ""
-
-    chunks = []
-    for key, index in sorted(normals.items(), key = operator.itemgetter(1)):
-        chunks.append(key)
-
-    return ",".join(generate_normal(n) for n in chunks)
-
-# #####################################################
-# Model exporter - vertex colors
-# #####################################################
-
-def extract_vertex_colors(mesh, colors, count):
-    color_layer = mesh.tessface_vertex_colors.active.data
-
-    for face_index, face in enumerate(get_faces(mesh)):
-
-        face_colors = color_layer[face_index]
-        face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-
-        for c in face_colors:
-            key = hexcolor(c)
-            if key not in colors:
-                colors[key] = count
-                count += 1
-
-    return count
-
-def generate_vertex_colors(colors, option_colors):
-    if not option_colors:
-        return ""
-
-    chunks = []
-    for key, index in sorted(colors.items(), key=operator.itemgetter(1)):
-        chunks.append(key)
-
-    return ",".join(generate_vertex_color(c) for c in chunks)
-
-# #####################################################
-# Model exporter - UVs
-# #####################################################
-
-def extract_uvs(mesh, uv_layers, counts):
-    for index, layer in enumerate(mesh.tessface_uv_textures):
-
-        if len(uv_layers) <= index:
-            uvs = {}
-            count = 0
-            uv_layers.append(uvs)
-            counts.append(count)
-        else:
-            uvs = uv_layers[index]
-            count = counts[index]
-
-        uv_layer = layer.data
-
-        for face_index, face in enumerate(get_faces(mesh)):
-
-            for uv_index, uv in enumerate(uv_layer[face_index].uv):
-
-                key = veckey2d(uv)
-                if key not in uvs:
-                    uvs[key] = count
-                    count += 1
-
-        counts[index] = count
-
-    return counts
-
-def generate_uvs(uv_layers, option_uv_coords):
-    if not option_uv_coords:
-        return "[]"
-
-    layers = []
-    for uvs in uv_layers:
-        chunks = []
-        for key, index in sorted(uvs.items(), key=operator.itemgetter(1)):
-            chunks.append(key)
-        layer = ",".join(generate_uv(n) for n in chunks)
-        layers.append(layer)
-
-    return ",".join("[%s]" % n for n in layers)
-
-# ##############################################################################
-# Model exporter - bones
-# (only the first armature will exported)
-# ##############################################################################
-
-def generate_bones(option_bones, flipyz):
-
-    if not option_bones or len(bpy.data.armatures) == 0:
-        return "", 0
-
-    hierarchy = []
-
-    armature = bpy.data.armatures[0]
-
-    TEMPLATE_BONE = '{"parent":%d,"name":"%s","pos":[%g,%g,%g],"rotq":[0,0,0,1]}'
-
-    for bone in armature.bones:
-        if bone.parent == None:
-            if flipyz:
-                joint = TEMPLATE_BONE % (-1, bone.name, bone.head.x, bone.head.z, -bone.head.y)
-                hierarchy.append(joint)
-            else:
-                joint = TEMPLATE_BONE % (-1, bone.name, bone.head.x, bone.head.y, bone.head.z)
-                hierarchy.append(joint)
-        else:
-            index = i = 0
-            for parent in armature.bones:
-                if parent.name == bone.parent.name:
-                    index = i
-                i += 1
-
-            position = bone.head_local - bone.parent.head_local
-
-            if flipyz:
-                joint = TEMPLATE_BONE % (index, bone.name, position.x, position.z, -position.y)
-                hierarchy.append(joint)
-            else:
-                joint = TEMPLATE_BONE % (index, bone.name, position.x, position.y, position.z)
-                hierarchy.append(joint)
-
-    bones_string = ",".join(hierarchy)
-
-    return bones_string, len(armature.bones)
-
-
-# ##############################################################################
-# Model exporter - skin indices and weights
-# ##############################################################################
-
-def generate_indices_and_weights(meshes, option_skinning):
-
-    if not option_skinning or len(bpy.data.armatures) == 0:
-        return "", ""
-
-    indices = []
-    weights = []
-
-    armature = bpy.data.armatures[0]
-
-    for mesh, object in meshes:
-
-        i = 0
-        mesh_index = -1
-
-        # find the original object
-
-        for obj in bpy.data.objects:
-            if obj.name == mesh.name or obj == object:
-                mesh_index = i
-            i += 1
-
-        if mesh_index == -1:
-            print("generate_indices: couldn't find object for mesh", mesh.name)
-            continue
-
-        object = bpy.data.objects[mesh_index]
-
-        for vertex in mesh.vertices:
-
-            # sort bones by influence
-
-            bone_array = []
-
-            for group in vertex.groups:
-                index = group.group
-                weight = group.weight
-
-                bone_array.append( (index, weight) )
-
-            bone_array.sort(key = operator.itemgetter(1), reverse=True)
-
-            # select first N bones
-
-            for i in range(MAX_INFLUENCES):
-
-                if i < len(bone_array):
-                    bone_proxy = bone_array[i]
-
-                    index = bone_proxy[0]
-                    weight = bone_proxy[1]
-
-                    for j, bone in enumerate(armature.bones):
-                        if object.vertex_groups[index].name == bone.name:
-                            indices.append('%d' % j)
-                            weights.append('%g' % weight)
-                            break
-
-                else:
-                    indices.append('0')
-                    weights.append('0')
-
-
-    indices_string = ",".join(indices)
-    weights_string = ",".join(weights)
-
-    return indices_string, weights_string
-
-
-# ##############################################################################
-# Model exporter - skeletal animation
-# (only the first action will exported)
-# ##############################################################################
-
-def generate_animation(option_animation_skeletal, option_frame_step, flipyz):
-
-    if not option_animation_skeletal or len(bpy.data.actions) == 0 or len(bpy.data.armatures) == 0:
-        return ""
-
-    # TODO: Add scaling influences
-
-    action = bpy.data.actions[0]
-    armature = bpy.data.armatures[0]
-
-    parents = []
-    parent_index = -1
-
-    fps = bpy.data.scenes[0].render.fps
-
-    end_frame = action.frame_range[1]
-    start_frame = action.frame_range[0]
-
-    frame_length = end_frame - start_frame
-
-    TEMPLATE_KEYFRAME_FULL  = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g],"scl":[1,1,1]}'
-    TEMPLATE_KEYFRAME       = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g]}'
-    TEMPLATE_KEYFRAME_POS   = '{"time":%g,"pos":[%g,%g,%g]}'
-    TEMPLATE_KEYFRAME_ROT   = '{"time":%g,"rot":[%g,%g,%g,%g]}'
-
-    for hierarchy in armature.bones:
-
-        keys = []
-
-        for frame in range(int(start_frame), int(end_frame / option_frame_step) + 1):
-
-            pos, pchange = position(hierarchy, frame * option_frame_step)
-            rot, rchange = rotation(hierarchy, frame * option_frame_step)
-
-            if flipyz:
-                px, py, pz = pos.x, pos.z, -pos.y
-                rx, ry, rz, rw = rot.x, rot.z, -rot.y, rot.w
-            else:
-                px, py, pz = pos.x, pos.y, pos.z
-                rx, ry, rz, rw = rot.x, rot.y, rot.z, rot.w
-
-            # START-FRAME: needs pos, rot and scl attributes (required frame)
-
-            if frame == int(start_frame):
-
-                time = (frame * option_frame_step - start_frame) / fps
-                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw)
-                keys.append(keyframe)
-
-            # END-FRAME: needs pos, rot and scl attributes with animation length (required frame)
-
-            elif frame == int(end_frame / option_frame_step):
-
-                time = frame_length / fps
-                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw)
-                keys.append(keyframe)
-
-            # MIDDLE-FRAME: needs only one of the attributes, can be an empty frame (optional frame)
-
-            elif pchange == True or rchange == True:
-
-                time = (frame * option_frame_step - start_frame) / fps
-
-                if pchange == True and rchange == True:
-                    keyframe = TEMPLATE_KEYFRAME % (time, px, py, pz, rx, ry, rz, rw)
-                elif pchange == True:
-                    keyframe = TEMPLATE_KEYFRAME_POS % (time, px, py, pz)
-                elif rchange == True:
-                    keyframe = TEMPLATE_KEYFRAME_ROT % (time, rx, ry, rz, rw)
-
-                keys.append(keyframe)
-
-        keys_string = ",".join(keys)
-        parent = '{"parent":%d,"keys":[%s]}' % (parent_index, keys_string)
-        parent_index += 1
-        parents.append(parent)
-
-    hierarchy_string = ",".join(parents)
-    animation_string = '"name":"%s","fps":%d,"length":%g,"hierarchy":[%s]' % (action.name, fps, (frame_length / fps), hierarchy_string)
-
-    return animation_string
-
-def handle_position_channel(channel, frame, position):
-
-    change = False
-
-    if channel.array_index in [0, 1, 2]:
-        for keyframe in channel.keyframe_points:
-            if keyframe.co[0] == frame:
-                change = True
-
-        value = channel.evaluate(frame)
-
-        if channel.array_index == 0:
-            position.x = value
-
-        if channel.array_index == 1:
-            position.y = value
-
-        if channel.array_index == 2:
-            position.z = value
-
-    return change
-
-def position(bone, frame):
-
-    position = mathutils.Vector((0,0,0))
-    change = False
-
-    action = bpy.data.actions[0]
-    ngroups = len(action.groups)
-
-
-
-    if ngroups > 0:
-
-        index = 0
-
-        for i in range(ngroups):
-            if action.groups[i].name == bone.name:
-                index = i
-
-        for channel in action.groups[index].channels:
-            if "location" in channel.data_path:
-                hasChanged = handle_position_channel(channel, frame, position)
-                change = change or hasChanged
-
-    else:
-
-        bone_label = '"%s"' % bone.name
-
-        for channel in action.fcurves:
-            data_path = channel.data_path
-            if bone_label in data_path and "location" in data_path:
-                hasChanged = handle_position_channel(channel, frame, position)
-                change = change or hasChanged
-
-    position = position * bone.matrix_local.inverted()
-
-    if bone.parent == None:
-
-        position.x += bone.head.x
-        position.y += bone.head.y
-        position.z += bone.head.z
-
-    else:
-
-        parent = bone.parent
-
-        parentInvertedLocalMatrix = parent.matrix_local.inverted()
-        parentHeadTailDiff = parent.tail_local - parent.head_local
-
-        position.x += (bone.head * parentInvertedLocalMatrix).x + parentHeadTailDiff.x
-        position.y += (bone.head * parentInvertedLocalMatrix).y + parentHeadTailDiff.y
-        position.z += (bone.head * parentInvertedLocalMatrix).z + parentHeadTailDiff.z
-
-    return position, change
-
-def handle_rotation_channel(channel, frame, rotation):
-
-    change = False
-
-    if channel.array_index in [0, 1, 2, 3]:
-
-        for keyframe in channel.keyframe_points:
-            if keyframe.co[0] == frame:
-                change = True
-
-        value = channel.evaluate(frame)
-
-        if channel.array_index == 1:
-            rotation.x = value
-
-        elif channel.array_index == 2:
-            rotation.y = value
-
-        elif channel.array_index == 3:
-            rotation.z = value
-
-        elif channel.array_index == 0:
-            rotation.w = value
-
-    return change
-
-def rotation(bone, frame):
-
-    # TODO: calculate rotation also from rotation_euler channels
-
-    rotation = mathutils.Vector((0,0,0,1))
-
-    change = False
-
-    action = bpy.data.actions[0]
-    ngroups = len(action.groups)
-
-    # animation grouped by bones
-
-    if ngroups > 0:
-
-        index = 0
-
-        for i in range(ngroups):
-            if action.groups[i].name == bone.name:
-                index = i
-
-        for channel in action.groups[index].channels:
-            if "quaternion" in channel.data_path:
-                hasChanged = handle_rotation_channel(channel, frame, rotation)
-                change = change or hasChanged
-
-    # animation in raw fcurves
-
-    else:
-
-        bone_label = '"%s"' % bone.name
-
-        for channel in action.fcurves:
-            data_path = channel.data_path
-            if bone_label in data_path and "quaternion" in data_path:
-                hasChanged = handle_rotation_channel(channel, frame, rotation)
-                change = change or hasChanged
-
-    rot3 = rotation.to_3d()
-    rotation.xyz = rot3 * bone.matrix_local.inverted()
-
-    return rotation, change
-
-# #####################################################
-# Model exporter - materials
-# #####################################################
-
-def generate_color(i):
-    """Generate hex color corresponding to integer.
-
-    Colors should have well defined ordering.
-    First N colors are hardcoded, then colors are random
-    (must seed random number  generator with deterministic value
-    before getting colors).
-    """
-
-    if i < len(COLORS):
-        #return "0x%06x" % COLORS[i]
-        return COLORS[i]
-    else:
-        #return "0x%06x" % int(0xffffff * random.random())
-        return int(0xffffff * random.random())
-
-def generate_mtl(materials):
-    """Generate dummy materials.
-    """
-
-    mtl = {}
-    for m in materials:
-        index = materials[m]
-        mtl[m] = {
-            "DbgName": m,
-            "DbgIndex": index,
-            "DbgColor": generate_color(index),
-            "vertexColors" : False
-        }
-    return mtl
-
-def value2string(v):
-    if type(v) == str and v[0:2] != "0x":
-        return '"%s"' % v
-    elif type(v) == bool:
-        return str(v).lower()
-    elif type(v) == list:
-        return "[%s]" % (", ".join(value2string(x) for x in v))
-    return str(v)
-
-def generate_materials(mtl, materials, draw_type):
-    """Generate JS array of materials objects
-    """
-
-    mtl_array = []
-    for m in mtl:
-        index = materials[m]
-
-        # add debug information
-        #  materials should be sorted according to how
-        #  they appeared in OBJ file (for the first time)
-        #  this index is identifier used in face definitions
-        mtl[m]['DbgName'] = m
-        mtl[m]['DbgIndex'] = index
-        mtl[m]['DbgColor'] = generate_color(index)
-
-        if draw_type in [ "BOUNDS", "WIRE" ]:
-            mtl[m]['wireframe'] = True
-            mtl[m]['DbgColor'] = 0xff0000
-
-        mtl_raw = ",\n".join(['\t\t"%s" : %s' % (n, value2string(v)) for n,v in sorted(mtl[m].items())])
-        mtl_string = "\t{\n%s\n\t}" % mtl_raw
-        mtl_array.append([index, mtl_string])
-
-    return ",\n\n".join([m for i,m in sorted(mtl_array)]), len(mtl_array)
-
-def extract_materials(mesh, scene, option_colors, option_copy_textures, filepath):
-    world = scene.world
-
-    materials = {}
-    for m in mesh.materials:
-        if m:
-            materials[m.name] = {}
-            material = materials[m.name]
-
-            material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
-                                        m.diffuse_intensity * m.diffuse_color[1],
-                                        m.diffuse_intensity * m.diffuse_color[2]]
-
-            material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
-                                         m.specular_intensity * m.specular_color[1],
-                                         m.specular_intensity * m.specular_color[2]]
-
-            material['colorAmbient'] = [m.ambient * material['colorDiffuse'][0],
-                                        m.ambient * material['colorDiffuse'][1],
-                                        m.ambient * material['colorDiffuse'][2]]
-
-            material['transparency'] = m.alpha
-
-            # not sure about mapping values to Blinn-Phong shader
-            # Blender uses INT from [1, 511] with default 0
-            # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
-
-            material["specularCoef"] = m.specular_hardness
-
-            textures = guess_material_textures(m)
-
-            handle_texture('diffuse', textures, material, filepath, option_copy_textures)
-            handle_texture('light', textures, material, filepath, option_copy_textures)
-            handle_texture('normal', textures, material, filepath, option_copy_textures)
-            handle_texture('specular', textures, material, filepath, option_copy_textures)
-            handle_texture('bump', textures, material, filepath, option_copy_textures)
-
-            material["vertexColors"] = m.THREE_useVertexColors and option_colors
-
-            # can't really use this reliably to tell apart Phong from Lambert
-            # as Blender defaults to non-zero specular color
-            #if m.specular_intensity > 0.0 and (m.specular_color[0] > 0 or m.specular_color[1] > 0 or m.specular_color[2] > 0):
-            #    material['shading'] = "Phong"
-            #else:
-            #    material['shading'] = "Lambert"
-
-            if textures['normal']:
-                material['shading'] = "Phong"
-            else:
-                material['shading'] = m.THREE_materialType
-
-            material['blending'] = m.THREE_blendingType
-            material['depthWrite'] = m.THREE_depthWrite
-            material['depthTest'] = m.THREE_depthTest
-            material['transparent'] = m.use_transparency
-
-    return materials
-
-def generate_materials_string(mesh, scene, option_colors, draw_type, option_copy_textures, filepath, offset):
-
-    random.seed(42) # to get well defined color order for debug materials
-
-    materials = {}
-    if mesh.materials:
-        for i, m in enumerate(mesh.materials):
-            mat_id = i + offset
-            if m:
-                materials[m.name] = mat_id
-            else:
-                materials["undefined_dummy_%0d" % mat_id] = mat_id
-
-
-    if not materials:
-        materials = { 'default': 0 }
-
-    # default dummy materials
-
-    mtl = generate_mtl(materials)
-
-    # extract real materials from the mesh
-
-    mtl.update(extract_materials(mesh, scene, option_colors, option_copy_textures, filepath))
-
-    return generate_materials(mtl, materials, draw_type)
-
-def handle_texture(id, textures, material, filepath, option_copy_textures):
-
-    if textures[id]:
-        texName     = 'map%s'       % id.capitalize()
-        repeatName  = 'map%sRepeat' % id.capitalize()
-        wrapName    = 'map%sWrap'   % id.capitalize()
-
-        slot = textures[id]['slot']
-        texture = textures[id]['texture']
-        image = texture.image
-        fname = extract_texture_filename(image)
-        material[texName] = fname
-
-        if option_copy_textures:
-            save_image(image, fname, filepath)
-
-        if texture.repeat_x != 1 or texture.repeat_y != 1:
-            material[repeatName] = [texture.repeat_x, texture.repeat_y]
-
-        if texture.extension == "REPEAT":
-            wrap_x = "repeat"
-            wrap_y = "repeat"
-
-            if texture.use_mirror_x:
-                wrap_x = "mirror"
-            if texture.use_mirror_y:
-                wrap_y = "mirror"
-
-            material[wrapName] = [wrap_x, wrap_y]
-
-        if slot.use_map_normal:
-            if slot.normal_factor != 1.0:
-                if id == "bump":
-                    material['mapBumpScale'] = slot.normal_factor
-                else:
-                    material['mapNormalFactor'] = slot.normal_factor
-
-
-# #####################################################
-# ASCII model generator
-# #####################################################
-
-def generate_ascii_model(meshes, morphs,
-                         scene,
-                         option_vertices,
-                         option_vertices_truncate,
-                         option_faces,
-                         option_normals,
-                         option_uv_coords,
-                         option_materials,
-                         option_colors,
-                         option_bones,
-                         option_skinning,
-                         align_model,
-                         flipyz,
-                         option_scale,
-                         option_copy_textures,
-                         filepath,
-                         option_animation_morph,
-                         option_animation_skeletal,
-                         option_frame_step):
-
-    vertices = []
-
-    vertex_offset = 0
-    vertex_offsets = []
-
-    nnormal = 0
-    normals = {}
-
-    ncolor = 0
-    colors = {}
-
-    nuvs = []
-    uv_layers = []
-
-    nmaterial = 0
-    materials = []
-
-    for mesh, object in meshes:
-
-        vertexUV = len(mesh.uv_textures) > 0
-        vertexColors = len(mesh.vertex_colors) > 0
-
-        mesh_extract_colors = option_colors and vertexColors
-        mesh_extract_uvs = option_uv_coords and vertexUV
-
-        if vertexUV:
-            active_uv_layer = mesh.uv_textures.active
-            if not active_uv_layer:
-                mesh_extract_uvs = False
-
-        if vertexColors:
-            active_col_layer = mesh.vertex_colors.active
-            if not active_col_layer:
-                mesh_extract_colors = False
-
-        vertex_offsets.append(vertex_offset)
-        vertex_offset += len(vertices)
-
-        vertices.extend(mesh.vertices[:])
-
-        if option_normals:
-            nnormal = extract_vertex_normals(mesh, normals, nnormal)
-
-        if mesh_extract_colors:
-            ncolor = extract_vertex_colors(mesh, colors, ncolor)
-
-        if mesh_extract_uvs:
-            nuvs = extract_uvs(mesh, uv_layers, nuvs)
-
-        if option_materials:
-            mesh_materials, nmaterial = generate_materials_string(mesh, scene, mesh_extract_colors, object.draw_type, option_copy_textures, filepath, nmaterial)
-            materials.append(mesh_materials)
-
-
-    morphTargets_string = ""
-    nmorphTarget = 0
-
-    if option_animation_morph:
-        chunks = []
-        for i, morphVertices in enumerate(morphs):
-            morphTarget = '{ "name": "%s_%06d", "vertices": [%s] }' % ("animation", i, morphVertices)
-            chunks.append(morphTarget)
-
-        morphTargets_string = ",\n\t".join(chunks)
-        nmorphTarget = len(morphs)
-
-    if align_model == 1:
-        center(vertices)
-    elif align_model == 2:
-        bottom(vertices)
-    elif align_model == 3:
-        top(vertices)
-
-    faces_string, nfaces = generate_faces(normals, uv_layers, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces)
-
-    bones_string, nbone = generate_bones(option_bones, flipyz)
-    indices_string, weights_string = generate_indices_and_weights(meshes, option_skinning)
-
-    materials_string = ",\n\n".join(materials)
-
-    model_string = TEMPLATE_MODEL_ASCII % {
-    "scale" : option_scale,
-
-    "uvs"       : generate_uvs(uv_layers, option_uv_coords),
-    "normals"   : generate_normals(normals, option_normals),
-    "colors"    : generate_vertex_colors(colors, option_colors),
-
-    "materials" : materials_string,
-
-    "vertices" : generate_vertices(vertices, option_vertices_truncate, option_vertices),
-
-    "faces"    : faces_string,
-
-    "morphTargets" : morphTargets_string,
-
-    "bones"     : bones_string,
-    "indices"   : indices_string,
-    "weights"   : weights_string,
-    "animation" : generate_animation(option_animation_skeletal, option_frame_step, flipyz)
-    }
-
-    text = TEMPLATE_FILE_ASCII % {
-    "nvertex"   : len(vertices),
-    "nface"     : nfaces,
-    "nuvs"      : ",".join("%d" % n for n in nuvs),
-    "nnormal"   : nnormal,
-    "ncolor"    : ncolor,
-    "nmaterial" : nmaterial,
-    "nmorphTarget": nmorphTarget,
-    "nbone"     : nbone,
-
-    "model"     : model_string
-    }
-
-
-    return text, model_string
-
-
-# #####################################################
-# Model exporter - export single mesh
-# #####################################################
-
-def extract_meshes(objects, scene, export_single_model, option_scale, flipyz):
-
-    meshes = []
-
-    for object in objects:
-
-        if object.type == "MESH" and object.THREE_exportGeometry:
-
-            # collapse modifiers into mesh
-
-            mesh = object.to_mesh(scene, True, 'RENDER')
-
-            if not mesh:
-                raise Exception("Error, could not get mesh data from object [%s]" % object.name)
-
-            # preserve original name
-
-            mesh.name = object.name
-
-            if export_single_model:
-
-                if flipyz:
-
-                    # that's what Blender's native export_obj.py does to flip YZ
-
-                    X_ROT = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
-                    mesh.transform(X_ROT * object.matrix_world)
-
-                else:
-                    mesh.transform(object.matrix_world)
-
-            mesh.calc_normals()
-            mesh.calc_tessface()
-            mesh.transform(mathutils.Matrix.Scale(option_scale, 4))
-            meshes.append([mesh, object])
-
-    return meshes
-
-def generate_mesh_string(objects, scene,
-                option_vertices,
-                option_vertices_truncate,
-                option_faces,
-                option_normals,
-                option_uv_coords,
-                option_materials,
-                option_colors,
-                option_bones,
-                option_skinning,
-                align_model,
-                flipyz,
-                option_scale,
-                export_single_model,
-                option_copy_textures,
-                filepath,
-                option_animation_morph,
-                option_animation_skeletal,
-                option_frame_step):
-
-    meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
-
-    morphs = []
-
-    if option_animation_morph:
-
-        original_frame = scene.frame_current # save animation state
-
-        scene_frames = range(scene.frame_start, scene.frame_end + 1, option_frame_step)
-
-        for frame in scene_frames:
-            scene.frame_set(frame, 0.0)
-
-            anim_meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
-
-            frame_vertices = []
-
-            for mesh, object in anim_meshes:
-                frame_vertices.extend(mesh.vertices[:])
-
-            morphVertices = generate_vertices(frame_vertices, option_vertices_truncate, option_vertices)
-            morphs.append(morphVertices)
-
-            # remove temp meshes
-
-            for mesh, object in anim_meshes:
-                bpy.data.meshes.remove(mesh)
-
-        scene.frame_set(original_frame, 0.0) # restore animation state
-
-
-    text, model_string = generate_ascii_model(meshes, morphs,
-                                scene,
-                                option_vertices,
-                                option_vertices_truncate,
-                                option_faces,
-                                option_normals,
-                                option_uv_coords,
-                                option_materials,
-                                option_colors,
-                                option_bones,
-                                option_skinning,
-                                align_model,
-                                flipyz,
-                                option_scale,
-                                option_copy_textures,
-                                filepath,
-                                option_animation_morph,
-                                option_animation_skeletal,
-                                option_frame_step)
-
-    # remove temp meshes
-
-    for mesh, object in meshes:
-        bpy.data.meshes.remove(mesh)
-
-    return text, model_string
-
-def export_mesh(objects,
-                scene, filepath,
-                option_vertices,
-                option_vertices_truncate,
-                option_faces,
-                option_normals,
-                option_uv_coords,
-                option_materials,
-                option_colors,
-                option_bones,
-                option_skinning,
-                align_model,
-                flipyz,
-                option_scale,
-                export_single_model,
-                option_copy_textures,
-                option_animation_morph,
-                option_animation_skeletal,
-                option_frame_step):
-
-    """Export single mesh"""
-
-    text, model_string = generate_mesh_string(objects,
-                scene,
-                option_vertices,
-                option_vertices_truncate,
-                option_faces,
-                option_normals,
-                option_uv_coords,
-                option_materials,
-                option_colors,
-                option_bones,
-                option_skinning,
-                align_model,
-                flipyz,
-                option_scale,
-                export_single_model,
-                option_copy_textures,
-                filepath,
-                option_animation_morph,
-                option_animation_skeletal,
-                option_frame_step)
-
-    write_file(filepath, text)
-
-    print("writing", filepath, "done")
-
-
-# #####################################################
-# Scene exporter - render elements
-# #####################################################
-
-def generate_vec4(vec):
-    return TEMPLATE_VEC4 % (vec[0], vec[1], vec[2], vec[3])
-
-def generate_vec3(vec):
-    return TEMPLATE_VEC3 % (vec[0], vec[1], vec[2])
-
-def generate_vec2(vec):
-    return TEMPLATE_VEC2 % (vec[0], vec[1])
-
-def generate_hex(number):
-    return TEMPLATE_HEX % number
-
-def generate_string(s):
-    return TEMPLATE_STRING % s
-
-def generate_string_list(src_list):
-    return ", ".join(generate_string(item) for item in src_list)
-
-def generate_section(label, content):
-    return TEMPLATE_SECTION % (label, content)
-
-def get_mesh_filename(mesh):
-    object_id = mesh["data"]["name"]
-    filename = "%s.js" % sanitize(object_id)
-    return filename
-
-def generate_material_id_list(materials):
-    chunks = []
-    for material in materials:
-        chunks.append(material.name)
-
-    return chunks
-
-def generate_group_id_list(obj):
-    chunks = []
-
-    for group in bpy.data.groups:
-        if obj.name in group.objects:
-            chunks.append(group.name)
-
-    return chunks
-
-def generate_bool_property(property):
-    if property:
-        return "true"
-    return "false"
-
-# #####################################################
-# Scene exporter - objects
-# #####################################################
-
-def generate_objects(data):
-    chunks = []
-
-    for obj in data["objects"]:
-
-        if obj.type == "MESH" and obj.THREE_exportGeometry:
-            object_id = obj.name
-
-            if len(obj.modifiers) > 0:
-                geo_name = obj.name
-            else:
-                geo_name = obj.data.name
-
-            geometry_id = "geo_%s" % geo_name
-
-            material_ids = generate_material_id_list(obj.material_slots)
-            group_ids = generate_group_id_list(obj)
-
-            position, quaternion, scale = obj.matrix_world.decompose()
-            rotation = quaternion.to_euler("XYZ")
-
-            material_string = ""
-            if len(material_ids) > 0:
-                material_string = generate_string_list(material_ids)
-
-            group_string = ""
-            if len(group_ids) > 0:
-                group_string = generate_string_list(group_ids)
-
-            castShadow = obj.THREE_castShadow
-            receiveShadow = obj.THREE_receiveShadow
-            doubleSided = obj.THREE_doubleSided
-
-            visible = True
-
-            geometry_string = generate_string(geometry_id)
-
-            object_string = TEMPLATE_OBJECT % {
-            "object_id"   : generate_string(object_id),
-            "geometry_id" : geometry_string,
-            "group_id"    : group_string,
-            "material_id" : material_string,
-
-            "position"    : generate_vec3(position),
-            "rotation"    : generate_vec3(rotation),
-            "quaternion"  : generate_vec4(quaternion),
-            "scale"       : generate_vec3(scale),
-
-            "castShadow"  : generate_bool_property(castShadow),
-            "receiveShadow"  : generate_bool_property(receiveShadow),
-            "doubleSided"  : generate_bool_property(doubleSided),
-            "visible"      : generate_bool_property(visible)
-            }
-            chunks.append(object_string)
-
-        elif obj.type == "EMPTY" or (obj.type == "MESH" and not obj.THREE_exportGeometry):
-
-            object_id = obj.name
-            group_ids = generate_group_id_list(obj)
-
-            position, quaternion, scale = obj.matrix_world.decompose()
-            rotation = quaternion.to_euler("XYZ")
-
-            group_string = ""
-            if len(group_ids) > 0:
-                group_string = generate_string_list(group_ids)
-
-            object_string = TEMPLATE_EMPTY % {
-            "object_id"   : generate_string(object_id),
-            "group_id"    : group_string,
-
-            "position"    : generate_vec3(position),
-            "rotation"    : generate_vec3(rotation),
-            "quaternion"  : generate_vec4(quaternion),
-            "scale"       : generate_vec3(scale)
-            }
-            chunks.append(object_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - geometries
-# #####################################################
-
-def generate_geometries(data):
-    chunks = []
-
-    geo_set = set()
-
-    for obj in data["objects"]:
-        if obj.type == "MESH" and obj.THREE_exportGeometry:
-
-            if len(obj.modifiers) > 0:
-                name = obj.name
-            else:
-                name = obj.data.name
-
-            if name not in geo_set:
-
-                geometry_id = "geo_%s" % name
-
-                if data["embed_meshes"]:
-
-                    embed_id = "emb_%s" % name
-
-                    geometry_string = TEMPLATE_GEOMETRY_EMBED % {
-                    "geometry_id" : generate_string(geometry_id),
-                    "embed_id"  : generate_string(embed_id)
-                    }
-
-                else:
-
-                    model_filename = os.path.basename(generate_mesh_filename(name, data["filepath"]))
-
-                    geometry_string = TEMPLATE_GEOMETRY_LINK % {
-                    "geometry_id" : generate_string(geometry_id),
-                    "model_file"  : generate_string(model_filename)
-                    }
-
-                chunks.append(geometry_string)
-
-                geo_set.add(name)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - textures
-# #####################################################
-
-def generate_textures_scene(data):
-    chunks = []
-
-    # TODO: extract just textures actually used by some objects in the scene
-
-    for texture in bpy.data.textures:
-
-        if texture.type == 'IMAGE' and texture.image:
-
-            img = texture.image
-
-            texture_id = img.name
-            texture_file = extract_texture_filename(img)
-
-            if data["copy_textures"]:
-                save_image(img, texture_file, data["filepath"])
-
-            extras = ""
-
-            if texture.repeat_x != 1 or texture.repeat_y != 1:
-                extras += ',\n        "repeat": [%g, %g]' % (texture.repeat_x, texture.repeat_y)
-
-            if texture.extension == "REPEAT":
-                wrap_x = "repeat"
-                wrap_y = "repeat"
-
-                if texture.use_mirror_x:
-                    wrap_x = "mirror"
-                if texture.use_mirror_y:
-                    wrap_y = "mirror"
-
-                extras += ',\n        "wrap": ["%s", "%s"]' % (wrap_x, wrap_y)
-
-            texture_string = TEMPLATE_TEXTURE % {
-            "texture_id"   : generate_string(texture_id),
-            "texture_file" : generate_string(texture_file),
-            "extras"       : extras
-            }
-            chunks.append(texture_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-def extract_texture_filename(image):
-    fn = bpy.path.abspath(image.filepath)
-    fn = os.path.normpath(fn)
-    fn_strip = os.path.basename(fn)
-    return fn_strip
-
-def save_image(img, name, fpath):
-    dst_dir = os.path.dirname(fpath)
-    dst_path = os.path.join(dst_dir, name)
-
-    ensure_folder_exist(dst_dir)
-
-    if img.packed_file:
-        img.save_render(dst_path)
-
-    else:
-        src_path = bpy.path.abspath(img.filepath)
-        shutil.copy(src_path, dst_dir)
-
-# #####################################################
-# Scene exporter - materials
-# #####################################################
-
-def extract_material_data(m, option_colors):
-    world = bpy.context.scene.world
-
-    material = { 'name': m.name }
-
-    material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
-                                m.diffuse_intensity * m.diffuse_color[1],
-                                m.diffuse_intensity * m.diffuse_color[2]]
-
-    material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
-                                 m.specular_intensity * m.specular_color[1],
-                                 m.specular_intensity * m.specular_color[2]]
-
-    material['colorAmbient'] = [m.ambient * material['colorDiffuse'][0],
-                                m.ambient * material['colorDiffuse'][1],
-                                m.ambient * material['colorDiffuse'][2]]
-
-    material['transparency'] = m.alpha
-
-    # not sure about mapping values to Blinn-Phong shader
-    # Blender uses INT from [1,511] with default 0
-    # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
-
-    material["specularCoef"] = m.specular_hardness
-
-    material["vertexColors"] = m.THREE_useVertexColors and option_colors
-
-    material['mapDiffuse'] = ""
-    material['mapLight'] = ""
-    material['mapSpecular'] = ""
-    material['mapNormal'] = ""
-    material['mapBump'] = ""
-
-    material['mapNormalFactor'] = 1.0
-    material['mapBumpScale'] = 1.0
-
-    textures = guess_material_textures(m)
-
-    if textures['diffuse']:
-        material['mapDiffuse'] = textures['diffuse']['texture'].image.name
-
-    if textures['light']:
-        material['mapLight'] = textures['light']['texture'].image.name
-
-    if textures['specular']:
-        material['mapSpecular'] = textures['specular']['texture'].image.name
-
-    if textures['normal']:
-        material['mapNormal'] = textures['normal']['texture'].image.name
-        if textures['normal']['slot'].use_map_normal:
-            material['mapNormalFactor'] = textures['normal']['slot'].normal_factor
-
-    if textures['bump']:
-        material['mapBump'] = textures['bump']['texture'].image.name
-        if textures['normal']['slot'].use_map_normal:
-            material['mapBumpScale'] = textures['normal']['slot'].normal_factor
-
-    material['shading'] = m.THREE_materialType
-    material['blending'] = m.THREE_blendingType
-    material['depthWrite'] = m.THREE_depthWrite
-    material['depthTest'] = m.THREE_depthTest
-    material['transparent'] = m.use_transparency
-
-    return material
-
-def guess_material_textures(material):
-    textures = {
-        'diffuse' : None,
-        'light'   : None,
-        'normal'  : None,
-        'specular': None,
-        'bump'    : None
-    }
-
-    # just take first textures of each, for the moment three.js materials can't handle more
-    # assume diffuse comes before lightmap, normalmap has checked flag
-
-    for i in range(len(material.texture_slots)):
-        slot = material.texture_slots[i]
-        if slot:
-            texture = slot.texture
-            if slot.use and texture and texture.type == 'IMAGE':
-
-                # normal map in Blender UI: textures => image sampling => normal map
-
-                if texture.use_normal_map:
-                    textures['normal'] = { "texture": texture, "slot": slot }
-
-                # bump map in Blender UI: textures => influence => geometry => normal
-
-                elif slot.use_map_normal:
-                    textures['bump'] = { "texture": texture, "slot": slot }
-
-                elif slot.use_map_specular or slot.use_map_hardness:
-                    textures['specular'] = { "texture": texture, "slot": slot }
-
-                else:
-                    if not textures['diffuse'] and not slot.blend_type == 'MULTIPLY':
-                        textures['diffuse'] = { "texture": texture, "slot": slot }
-
-                    else:
-                        textures['light'] = { "texture": texture, "slot": slot }
-
-                if textures['diffuse'] and textures['normal'] and textures['light'] and textures['specular'] and textures['bump']:
-                    break
-
-    return textures
-
-def generate_material_string(material):
-
-    material_id = material["name"]
-
-    # default to Lambert
-
-    shading = material.get("shading", "Lambert")
-
-    # normal and bump mapped materials must use Phong
-    # to get all required parameters for normal shader
-
-    if material['mapNormal'] or material['mapBump']:
-        shading = "Phong"
-
-    type_map = {
-    "Lambert"   : "MeshLambertMaterial",
-    "Phong"     : "MeshPhongMaterial"
-    }
-
-    material_type = type_map.get(shading, "MeshBasicMaterial")
-
-    parameters = '"color": %d' % rgb2int(material["colorDiffuse"])
-    parameters += ', "opacity": %.2g' % material["transparency"]
-
-    if shading == "Phong":
-        parameters += ', "ambient": %d' % rgb2int(material["colorAmbient"])
-        parameters += ', "specular": %d' % rgb2int(material["colorSpecular"])
-        parameters += ', "shininess": %.1g' % material["specularCoef"]
-
-    colorMap = material['mapDiffuse']
-    lightMap = material['mapLight']
-    specularMap = material['mapSpecular']
-    normalMap = material['mapNormal']
-    bumpMap = material['mapBump']
-    normalMapFactor = material['mapNormalFactor']
-    bumpMapScale = material['mapBumpScale']
-
-    if colorMap:
-        parameters += ', "map": %s' % generate_string(colorMap)
-    if lightMap:
-        parameters += ', "lightMap": %s' % generate_string(lightMap)
-    if specularMap:
-        parameters += ', "specularMap": %s' % generate_string(specularMap)
-    if normalMap:
-        parameters += ', "normalMap": %s' % generate_string(normalMap)
-    if bumpMap:
-        parameters += ', "bumpMap": %s' % generate_string(bumpMap)
-
-    if normalMapFactor != 1.0:
-        parameters += ', "normalMapFactor": %g' % normalMapFactor
-
-    if bumpMapScale != 1.0:
-        parameters += ', "bumpMapScale": %g' % bumpMapScale
-
-    if material['vertexColors']:
-        parameters += ', "vertexColors": "vertex"'
-
-    if material['transparent']:
-        parameters += ', "transparent": true'
-
-    parameters += ', "blending": "%s"' % material['blending']
-
-    if not material['depthWrite']:
-        parameters += ', "depthWrite": false'
-
-    if not material['depthTest']:
-        parameters += ', "depthTest": false'
-
-
-    material_string = TEMPLATE_MATERIAL_SCENE % {
-    "material_id" : generate_string(material_id),
-    "type"        : generate_string(material_type),
-    "parameters"  : parameters
-    }
-
-    return material_string
-
-def generate_materials_scene(data):
-    chunks = []
-
-    # TODO: extract just materials actually used by some objects in the scene
-
-    for m in bpy.data.materials:
-        material = extract_material_data(m, data["use_colors"])
-        material_string = generate_material_string(material)
-        chunks.append(material_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - cameras
-# #####################################################
-
-def generate_cameras(data):
-    if data["use_cameras"]:
-
-        cams = bpy.data.objects
-        cams = [ob for ob in cams if (ob.type == 'CAMERA' and ob.select)]
-
-        chunks = []
-
-        if not cams:
-            camera = DEFAULTS["camera"]
-
-            if camera["type"] == "perspective":
-
-                camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
-                "camera_id" : generate_string(camera["name"]),
-                "fov"       : camera["fov"],
-                "aspect"    : camera["aspect"],
-                "near"      : camera["near"],
-                "far"       : camera["far"],
-                "position"  : generate_vec3(camera["position"]),
-                "target"    : generate_vec3(camera["target"])
-                }
-
-            elif camera["type"] == "ortho":
-
-                camera_string = TEMPLATE_CAMERA_ORTHO % {
-                "camera_id" : generate_string(camera["name"]),
-                "left"      : camera["left"],
-                "right"     : camera["right"],
-                "top"       : camera["top"],
-                "bottom"    : camera["bottom"],
-                "near"      : camera["near"],
-                "far"       : camera["far"],
-                "position"  : generate_vec3(camera["position"]),
-                "target"    : generate_vec3(camera["target"])
-                }
-
-            chunks.append(camera_string)
-
-        else:
-
-            for cameraobj in cams:
-                camera = bpy.data.cameras[cameraobj.name]
-
-                # TODO:
-                #   Support more than perspective camera
-                #   Calculate a target/lookat
-                #   Get correct aspect ratio
-                if camera.id_data.type == "PERSP":
-
-                    camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
-                    "camera_id" : generate_string(camera.name),
-                    "fov"       : (camera.angle / 3.14) * 180.0,
-                    "aspect"    : 1.333,
-                    "near"      : camera.clip_start,
-                    "far"       : camera.clip_end,
-                    "position"  : generate_vec3([cameraobj.location[0], -cameraobj.location[1], cameraobj.location[2]]),
-                    "target"    : generate_vec3([0, 0, 0])
-                    }
-
-                chunks.append(camera_string)
-
-        return ",\n\n".join(chunks)
-
-    return ""
-
-# #####################################################
-# Scene exporter - lights
-# #####################################################
-
-def generate_lights(data):
-
-    if data["use_lights"]:
-
-        lights = data.get("lights", [])
-        if not lights:
-            lights.append(DEFAULTS["light"])
-
-        chunks = []
-        for light in lights:
-
-            if light["type"] == "directional":
-                light_string = TEMPLATE_LIGHT_DIRECTIONAL % {
-                "light_id"      : generate_string(light["name"]),
-                "direction"     : generate_vec3(light["direction"]),
-                "color"         : rgb2int(light["color"]),
-                "intensity"     : light["intensity"]
-                }
-
-            elif light["type"] == "point":
-                light_string = TEMPLATE_LIGHT_POINT % {
-                "light_id"      : generate_string(light["name"]),
-                "position"      : generate_vec3(light["position"]),
-                "color"         : rgb2int(light["color"]),
-                "intensity"     : light["intensity"]
-                }
-
-            chunks.append(light_string)
-
-        return ",\n\n".join(chunks)
-
-    return ""
-
-# #####################################################
-# Scene exporter - embedded meshes
-# #####################################################
-
-def generate_embeds(data):
-
-    if data["embed_meshes"]:
-
-        chunks = []
-
-        for e in data["embeds"]:
-
-            embed = '"emb_%s": {%s}' % (e, data["embeds"][e])
-            chunks.append(embed)
-
-        return ",\n\n".join(chunks)
-
-    return ""
-
-# #####################################################
-# Scene exporter - generate ASCII scene
-# #####################################################
-
-def generate_ascii_scene(data):
-
-    objects, nobjects = generate_objects(data)
-    geometries, ngeometries = generate_geometries(data)
-    textures, ntextures = generate_textures_scene(data)
-    materials, nmaterials = generate_materials_scene(data)
-
-    cameras = generate_cameras(data)
-    lights = generate_lights(data)
-
-    embeds = generate_embeds(data)
-
-    basetype = "relativeTo"
-
-    if data["base_html"]:
-        basetype += "HTML"
-    else:
-        basetype += "Scene"
-
-    sections = [
-    ["objects",    objects],
-    ["geometries", geometries],
-    ["textures",   textures],
-    ["materials",  materials],
-    ["cameras",    cameras],
-    ["lights",     lights],
-    ["embeds",     embeds]
-    ]
-
-    chunks = []
-    for label, content in sections:
-        if content:
-            chunks.append(generate_section(label, content))
-
-    sections_string = "\n".join(chunks)
-
-    default_camera = ""
-    if data["use_cameras"]:
-        cams = [ob for ob in bpy.data.objects if (ob.type == 'CAMERA' and ob.select)]
-        if not cams:
-            default_camera = "default_camera"
-        else:
-            default_camera = cams[0].name
-
-    parameters = {
-    "fname"     : data["source_file"],
-
-    "sections"  : sections_string,
-
-    "bgcolor"   : generate_vec3(DEFAULTS["bgcolor"]),
-    "bgalpha"   : DEFAULTS["bgalpha"],
-    "defcamera" :  generate_string(default_camera),
-
-    "nobjects"      : nobjects,
-    "ngeometries"   : ngeometries,
-    "ntextures"     : ntextures,
-    "basetype"      : generate_string(basetype),
-    "nmaterials"    : nmaterials,
-
-    "position"      : generate_vec3(DEFAULTS["position"]),
-    "rotation"      : generate_vec3(DEFAULTS["rotation"]),
-    "scale"         : generate_vec3(DEFAULTS["scale"])
-    }
-
-    text = TEMPLATE_SCENE_ASCII % parameters
-
-    return text
-
-def export_scene(scene, filepath, flipyz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds, option_url_base_html, option_copy_textures):
-
-    source_file = os.path.basename(bpy.data.filepath)
-
-    # objects are contained in scene and linked groups
-    objects = []
-
-    # get scene objects
-    sceneobjects = scene.objects
-    for obj in sceneobjects:
-      objects.append(obj)
-
-    # get linked group objcts
-    for group in bpy.data.groups:
-       for object in group.objects:
-          objects.append(object)
-
-    scene_text = ""
-    data = {
-    "scene"        : scene,
-    "objects"      : objects,
-    "embeds"       : embeds,
-    "source_file"  : source_file,
-    "filepath"     : filepath,
-    "flipyz"       : flipyz,
-    "use_colors"   : option_colors,
-    "use_lights"   : option_lights,
-    "use_cameras"  : option_cameras,
-    "embed_meshes" : option_embed_meshes,
-    "base_html"    : option_url_base_html,
-    "copy_textures": option_copy_textures
-    }
-    scene_text += generate_ascii_scene(data)
-
-    write_file(filepath, scene_text)
-
-# #####################################################
-# Main
-# #####################################################
-
-def save(operator, context, filepath = "",
-         option_flip_yz = True,
-         option_vertices = True,
-         option_vertices_truncate = False,
-         option_faces = True,
-         option_normals = True,
-         option_uv_coords = True,
-         option_materials = True,
-         option_colors = True,
-         option_bones = True,
-         option_skinning = True,
-         align_model = 0,
-         option_export_scene = False,
-         option_lights = False,
-         option_cameras = False,
-         option_scale = 1.0,
-         option_embed_meshes = True,
-         option_url_base_html = False,
-         option_copy_textures = False,
-         option_animation_morph = False,
-         option_animation_skeletal = False,
-         option_frame_step = 1,
-         option_all_meshes = True):
-
-    #print("URL TYPE", option_url_base_html)
-
-    filepath = ensure_extension(filepath, '.js')
-
-    scene = context.scene
-
-    if scene.objects.active:
-        bpy.ops.object.mode_set(mode='OBJECT')
-
-    if option_all_meshes:
-        sceneobjects = scene.objects
-    else:
-        sceneobjects = context.selected_objects
-
-    # objects are contained in scene and linked groups
-    objects = []
-
-    # get scene objects
-    for obj in sceneobjects:
-      objects.append(obj)
-
-    # get objects in linked groups
-    for group in bpy.data.groups:
-       for object in group.objects:
-          objects.append(object)
-
-    if option_export_scene:
-
-        geo_set = set()
-        embeds = {}
-
-        for object in objects:
-            if object.type == "MESH" and object.THREE_exportGeometry:
-
-                # create extra copy of geometry with applied modifiers
-                # (if they exist)
-
-                if len(object.modifiers) > 0:
-                    name = object.name
-
-                # otherwise can share geometry
-
-                else:
-                    name = object.data.name
-
-                if name not in geo_set:
-
-                    if option_embed_meshes:
-
-                        text, model_string = generate_mesh_string([object], scene,
-                                                        option_vertices,
-                                                        option_vertices_truncate,
-                                                        option_faces,
-                                                        option_normals,
-                                                        option_uv_coords,
-                                                        option_materials,
-                                                        option_colors,
-                                                        option_bones,
-                                                        option_skinning,
-                                                        False,          # align_model
-                                                        option_flip_yz,
-                                                        option_scale,
-                                                        False,          # export_single_model
-                                                        False,          # option_copy_textures
-                                                        filepath,
-                                                        option_animation_morph,
-                                                        option_animation_skeletal,
-                                                        option_frame_step)
-
-                        embeds[name] = model_string
-
-                    else:
-
-                        fname = generate_mesh_filename(name, filepath)
-                        export_mesh([object], scene,
-                                    fname,
-                                    option_vertices,
-                                    option_vertices_truncate,
-                                    option_faces,
-                                    option_normals,
-                                    option_uv_coords,
-                                    option_materials,
-                                    option_colors,
-                                    option_bones,
-                                    option_skinning,
-                                    False,          # align_model
-                                    option_flip_yz,
-                                    option_scale,
-                                    False,          # export_single_model
-                                    option_copy_textures,
-                                    option_animation_morph,
-                                    option_animation_skeletal,
-                                    option_frame_step)
-
-                    geo_set.add(name)
-
-        export_scene(scene, filepath,
-                     option_flip_yz,
-                     option_colors,
-                     option_lights,
-                     option_cameras,
-                     option_embed_meshes,
-                     embeds,
-                     option_url_base_html,
-                     option_copy_textures)
-
-    else:
-
-        export_mesh(objects, scene, filepath,
-                    option_vertices,
-                    option_vertices_truncate,
-                    option_faces,
-                    option_normals,
-                    option_uv_coords,
-                    option_materials,
-                    option_colors,
-                    option_bones,
-                    option_skinning,
-                    align_model,
-                    option_flip_yz,
-                    option_scale,
-                    True,            # export_single_model
-                    option_copy_textures,
-                    option_animation_morph,
-                    option_animation_skeletal,
-                    option_frame_step)
-
-    return {'FINISHED'}

+ 0 - 633
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/import_threejs.py

@@ -1,633 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-"""
-Blender importer for Three.js (ASCII JSON format).
-
-"""
-
-import os
-import time
-import json
-import bpy
-import mathutils
-from mathutils.geometry import tesselate_polygon
-from bpy_extras.image_utils import load_image
-
-# #####################################################
-# Generators
-# #####################################################
-def setColor(c, t):
-    c.r = t[0]
-    c.g = t[1]
-    c.b = t[2]
-
-def create_texture(filename, modelpath):
-    name = filename
-    texture = bpy.data.textures.new(name, type='IMAGE')
-
-    image = load_image(filename, modelpath)
-    has_data = False
-
-    if image:
-        texture.image = image
-        has_data = image.has_data
-
-    return texture
-
-def create_materials(data, modelpath):
-    materials = []
-    materials_data = data.get("materials", [])
-
-    for i, m in enumerate(materials_data):
-
-        name = m.get("DbgName", "material_%d" % i)
-
-        colorAmbient = m.get("colorAmbient", None)
-        colorDiffuse = m.get("colorDiffuse", None)
-        colorSpecular = m.get("colorSpecular", None)
-        alpha = m.get("transparency", 1.0)
-        specular_hardness = m.get("specularCoef", 0)
-
-        mapDiffuse = m.get("mapDiffuse", None)
-        mapLightmap = m.get("mapLightmap", None)
-
-        vertexColorsType = m.get("vertexColors", False)
-
-        useVertexColors = False
-        if vertexColorsType:
-            useVertexColors = True
-
-        material = bpy.data.materials.new(name)
-
-        material.THREE_useVertexColors = useVertexColors
-
-        if colorDiffuse:
-            setColor(material.diffuse_color, colorDiffuse)
-            material.diffuse_intensity = 1.0
-
-        if colorSpecular:
-            setColor(material.specular_color, colorSpecular)
-            material.specular_intensity = 1.0
-
-        if alpha < 1.0:
-            material.alpha = alpha
-            material.use_transparency = True
-
-        if specular_hardness:
-            material.specular_hardness = specular_hardness
-
-        if mapDiffuse:
-            texture = create_texture(mapDiffuse, modelpath)
-            mtex = material.texture_slots.add()
-            mtex.texture = texture
-            mtex.texture_coords = 'UV'
-            mtex.use = True
-            mtex.use_map_color_diffuse = True
-
-            material.active_texture = texture
-
-        materials.append(material)
-
-    return materials
-
-def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate_normals):
-
-    faces         = face_data["faces"]
-    vertexNormals = face_data["vertexNormals"]
-    vertexColors  = face_data["vertexColors"]
-    vertexUVs     = face_data["vertexUVs"]
-    faceMaterials = face_data["materials"]
-    faceColors    = face_data["faceColors"]
-
-    edges = []
-
-    # Create a new mesh
-
-    me = bpy.data.meshes.new(name)
-    me.from_pydata(vertices, edges, faces)
-
-    # Handle normals
-
-    if not recalculate_normals:
-        me.update(calc_edges = True)
-
-    if face_data["hasVertexNormals"]:
-
-        print("setting vertex normals")
-
-        for fi in range(len(faces)):
-
-            if vertexNormals[fi]:
-
-                #print("setting face %i with %i vertices" % (fi, len(normals[fi])))
-
-                # if me.update() is called after setting vertex normals
-                # setting face.use_smooth overrides these normals
-                #  - this fixes weird shading artefacts (seems to come from sharing
-                #    of vertices between faces, didn't find a way how to set vertex normals
-                #    per face use of vertex as opposed to per vertex),
-                #  - probably this just overrides all custom vertex normals
-                #  - to preserve vertex normals from the original data
-                #    call me.update() before setting them
-
-                me.faces[fi].use_smooth = True
-
-                if not recalculate_normals:
-                    for j in range(len(vertexNormals[fi])):
-
-                        vertexNormal = vertexNormals[fi][j]
-
-                        x = vertexNormal[0]
-                        y = vertexNormal[1]
-                        z = vertexNormal[2]
-
-                        if flipYZ:
-                            tmp = y
-                            y = -z
-                            z = tmp
-
-                            # flip normals (this make them look consistent with the original before export)
-
-                            #x = -x
-                            #y = -y
-                            #z = -z
-
-                        vi = me.faces[fi].vertices[j]
-
-                        me.vertices[vi].normal.x = x
-                        me.vertices[vi].normal.y = y
-                        me.vertices[vi].normal.z = z
-
-    if recalculate_normals:
-        me.update(calc_edges = True)
-
-    # Handle colors
-
-    if face_data["hasVertexColors"]:
-
-        print("setting vertex colors")
-
-        me.vertex_colors.new("vertex_color_layer_0")
-
-        for fi in range(len(faces)):
-
-            if vertexColors[fi]:
-
-                face_colors = me.vertex_colors[0].data[fi]
-                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-
-                for vi in range(len(vertexColors[fi])):
-
-                    r = vertexColors[fi][vi][0]
-                    g = vertexColors[fi][vi][1]
-                    b = vertexColors[fi][vi][2]
-
-                    face_colors[vi].r = r
-                    face_colors[vi].g = g
-                    face_colors[vi].b = b
-
-    elif face_data["hasFaceColors"]:
-
-        print("setting vertex colors from face colors")
-
-        me.vertex_colors.new("vertex_color_layer_0")
-
-        for fi in range(len(faces)):
-
-            if faceColors[fi]:
-
-                r = faceColors[fi][0]
-                g = faceColors[fi][1]
-                b = faceColors[fi][2]
-
-                face_colors = me.vertex_colors[0].data[fi]
-                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-
-                for vi in range(len(faces[fi])):
-
-                    face_colors[vi].r = r
-                    face_colors[vi].g = g
-                    face_colors[vi].b = b
-
-    # Handle uvs
-
-    if face_data["hasVertexUVs"]:
-
-        print("setting vertex uvs")
-
-        for li, layer in enumerate(vertexUVs):
-
-            me.uv_textures.new("uv_layer_%d" % li)
-
-            for fi in range(len(faces)):
-
-                if layer[fi]:
-
-                    uv_face = me.uv_textures[li].data[fi]
-                    face_uvs = uv_face.uv1, uv_face.uv2, uv_face.uv3, uv_face.uv4
-
-                    for vi in range(len(layer[fi])):
-
-                        u = layer[fi][vi][0]
-                        v = layer[fi][vi][1]
-
-                        face_uvs[vi].x = u
-                        face_uvs[vi].y = v
-
-                    active_texture = materials[faceMaterials[fi]].active_texture
-
-                    if active_texture:
-                        uv_face.image = active_texture.image
-
-
-    # Handle materials # 1
-
-    if face_data["hasMaterials"]:
-
-
-        print("setting materials (mesh)")
-
-        for m in materials:
-
-            me.materials.append(m)
-
-        print("setting materials (faces)")
-
-        for fi in range(len(faces)):
-
-            if faceMaterials[fi] >= 0:
-
-                me.faces[fi].material_index = faceMaterials[fi]
-
-    # Create a new object
-
-    ob = bpy.data.objects.new(name, me)
-    ob.data = me                                # link the mesh data to the object
-
-
-    scene = bpy.context.scene                   # get the current scene
-    scene.objects.link(ob)                      # link the object into the scene
-
-    ob.location = scene.cursor_location         # position object at 3d-cursor
-
-
-# #####################################################
-# Faces
-# #####################################################
-
-def extract_faces(data):
-
-    result = {
-    "faces"         : [],
-    "materials"     : [],
-    "faceUVs"       : [],
-    "vertexUVs"     : [],
-    "faceNormals"   : [],
-    "vertexNormals" : [],
-    "faceColors"    : [],
-    "vertexColors"  : [],
-
-    "hasVertexNormals"  : False,
-    "hasVertexUVs"      : False,
-    "hasVertexColors"   : False,
-    "hasFaceColors"     : False,
-    "hasMaterials"      : False
-    }
-
-    faces = data.get("faces", [])
-    normals = data.get("normals", [])
-    colors = data.get("colors", [])
-
-    offset = 0
-    zLength = len(faces)
-
-    # disregard empty arrays
-
-    nUvLayers = 0
-
-    for layer in data["uvs"]:
-
-        if len(layer) > 0:
-            nUvLayers += 1
-            result["faceUVs"].append([])
-            result["vertexUVs"].append([])
-
-
-    while ( offset < zLength ):
-
-        type = faces[ offset ]
-        offset += 1
-
-        isQuad          	= isBitSet( type, 0 )
-        hasMaterial         = isBitSet( type, 1 )
-        hasFaceUv           = isBitSet( type, 2 )
-        hasFaceVertexUv     = isBitSet( type, 3 )
-        hasFaceNormal       = isBitSet( type, 4 )
-        hasFaceVertexNormal = isBitSet( type, 5 )
-        hasFaceColor	    = isBitSet( type, 6 )
-        hasFaceVertexColor  = isBitSet( type, 7 )
-
-        #print("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor)
-
-        result["hasVertexUVs"] = result["hasVertexUVs"] or hasFaceVertexUv
-        result["hasVertexNormals"] = result["hasVertexNormals"] or hasFaceVertexNormal
-        result["hasVertexColors"] = result["hasVertexColors"] or hasFaceVertexColor
-        result["hasFaceColors"] = result["hasFaceColors"] or hasFaceColor
-        result["hasMaterials"] = result["hasMaterials"] or hasMaterial
-
-        # vertices
-
-        if isQuad:
-
-            a = faces[ offset ]
-            offset += 1
-
-            b = faces[ offset ]
-            offset += 1
-
-            c = faces[ offset ]
-            offset += 1
-
-            d = faces[ offset ]
-            offset += 1
-
-            face = [a, b, c, d]
-
-            nVertices = 4
-
-        else:
-
-            a = faces[ offset ]
-            offset += 1
-
-            b = faces[ offset ]
-            offset += 1
-
-            c = faces[ offset ]
-            offset += 1
-
-            face = [a, b, c]
-
-            nVertices = 3
-
-        result["faces"].append(face)
-
-        # material
-
-        if hasMaterial:
-
-            materialIndex = faces[ offset ]
-            offset += 1
-
-        else:
-
-            materialIndex = -1
-
-        result["materials"].append(materialIndex)
-
-        # uvs
-
-        for i in range(nUvLayers):
-
-            faceUv = None
-
-            if hasFaceUv:
-
-                uvLayer = data["uvs"][ i ]
-
-                uvIndex = faces[ offset ]
-                offset += 1
-
-                u = uvLayer[ uvIndex * 2 ]
-                v = uvLayer[ uvIndex * 2 + 1 ]
-
-                faceUv = [u, v]
-
-            result["faceUVs"][i].append(faceUv)
-
-
-            if hasFaceVertexUv:
-
-                uvLayer = data["uvs"][ i ]
-
-                vertexUvs = []
-
-                for j in range(nVertices):
-
-                    uvIndex = faces[ offset ]
-                    offset += 1
-
-                    u = uvLayer[ uvIndex * 2 ]
-                    v = uvLayer[ uvIndex * 2 + 1 ]
-
-                    vertexUvs.append([u, v])
-
-            result["vertexUVs"][i].append(vertexUvs)
-
-
-        if hasFaceNormal:
-
-            normalIndex = faces[ offset ] * 3
-            offset += 1
-
-            x = normals[ normalIndex ]
-            y = normals[ normalIndex + 1 ]
-            z = normals[ normalIndex + 2 ]
-
-            faceNormal = [x, y, z]
-
-        else:
-
-            faceNormal = None
-
-        result["faceNormals"].append(faceNormal)
-
-
-        if hasFaceVertexNormal:
-
-            vertexNormals = []
-
-            for j in range(nVertices):
-
-                normalIndex = faces[ offset ] * 3
-                offset += 1
-
-                x = normals[ normalIndex ]
-                y = normals[ normalIndex + 1 ]
-                z = normals[ normalIndex + 2 ]
-
-                vertexNormals.append( [x, y, z] )
-
-
-        else:
-
-            vertexNormals = None
-
-        result["vertexNormals"].append(vertexNormals)
-
-
-        if hasFaceColor:
-
-            colorIndex = faces[ offset ]
-            offset += 1
-
-            faceColor = hexToTuple( colors[ colorIndex ] )
-
-        else:
-
-            faceColor = None
-
-        result["faceColors"].append(faceColor)
-
-
-        if hasFaceVertexColor:
-
-            vertexColors = []
-
-            for j in range(nVertices):
-
-                colorIndex = faces[ offset ]
-                offset += 1
-
-                color = hexToTuple( colors[ colorIndex ] )
-                vertexColors.append( color )
-
-        else:
-
-            vertexColors = None
-
-        result["vertexColors"].append(vertexColors)
-
-
-    return result
-
-# #####################################################
-# Utils
-# #####################################################
-
-def hexToTuple( hexColor ):
-    r = (( hexColor >> 16 ) & 0xff) / 255.0
-    g = (( hexColor >> 8 ) & 0xff) / 255.0
-    b = ( hexColor & 0xff) / 255.0
-    return (r, g, b)
-
-def isBitSet(value, position):
-    return value & ( 1 << position )
-
-def splitArray(data, chunkSize):
-    result = []
-    chunk = []
-    for i in range(len(data)):
-        if i > 0 and i % chunkSize == 0:
-            result.append(chunk)
-            chunk = []
-        chunk.append(data[i])
-    result.append(chunk)
-    return result
-
-
-def extract_json_string(text):
-    marker_begin = "var model ="
-    marker_end = "postMessage"
-
-    start = text.find(marker_begin) + len(marker_begin)
-    end = text.find(marker_end)
-    end = text.rfind("}", start, end)
-    return text[start:end+1].strip()
-
-def get_name(filepath):
-    return os.path.splitext(os.path.basename(filepath))[0]
-
-def get_path(filepath):
-    return os.path.dirname(filepath)
-
-# #####################################################
-# Parser
-# #####################################################
-
-def load(operator, context, filepath, option_flip_yz = True, recalculate_normals = True, option_worker = False):
-
-    print('\nimporting %r' % filepath)
-
-    time_main = time.time()
-
-    print("\tparsing JSON file...")
-
-    time_sub = time.time()
-
-    file = open(filepath, 'rU')
-    rawcontent = file.read()
-    file.close()
-
-    if option_worker:
-        json_string = extract_json_string(rawcontent)
-    else:
-        json_string = rawcontent
-    data = json.loads( json_string )
-
-    time_new = time.time()
-
-    print('parsing %.4f sec' % (time_new - time_sub))
-
-    time_sub = time_new
-
-    # flip YZ
-
-    vertices = splitArray(data["vertices"], 3)
-
-    if option_flip_yz:
-        vertices[:] = [(v[0], -v[2], v[1]) for v in vertices]
-
-    # extract faces
-
-    face_data = extract_faces(data)
-
-    # deselect all
-
-    bpy.ops.object.select_all(action='DESELECT')
-
-    nfaces = len(face_data["faces"])
-    nvertices = len(vertices)
-    nnormals = len(data.get("normals", [])) / 3
-    ncolors = len(data.get("colors", [])) / 3
-    nuvs = len(data.get("uvs", [])) / 2
-    nmaterials = len(data.get("materials", []))
-
-    print('\tbuilding geometry...\n\tfaces:%i, vertices:%i, vertex normals: %i, vertex uvs: %i, vertex colors: %i, materials: %i ...' % (
-        nfaces, nvertices, nnormals, nuvs, ncolors, nmaterials ))
-
-    # Create materials
-
-    materials = create_materials(data, get_path(filepath))
-
-    # Create new obj
-
-    create_mesh_object(get_name(filepath), vertices, materials, face_data, option_flip_yz, recalculate_normals)
-
-    scene = bpy.context.scene
-    scene.update()
-
-    time_new = time.time()
-
-    print('finished importing: %r in %.4f sec.' % (filepath, (time_new - time_main)))
-    return {'FINISHED'}
-
-
-if __name__ == "__main__":
-    register()

+ 0 - 454
utils/exporters/blender/2.64/scripts/addons/io_mesh_threejs/__init__.py

@@ -1,454 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# ################################################################
-# Init
-# ################################################################
-
-
-bl_info = {
-    "name": "three.js format",
-    "author": "mrdoob, kikko, alteredq, remoe, pxf, n3tfr34k",
-    "version": (1, 4, 0),
-    "blender": (2, 6, 4),
-    "api": 35622,
-    "location": "File > Import-Export",
-    "description": "Import-Export three.js meshes",
-    "warning": "",
-    "wiki_url": "https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender",
-    "tracker_url": "https://github.com/mrdoob/three.js/issues",
-    "category": "Import-Export"}
-
-# To support reload properly, try to access a package var,
-# if it's there, reload everything
-
-import bpy
-
-if "bpy" in locals():
-    import imp
-    if "export_threejs" in locals():
-        imp.reload(export_threejs)
-    if "import_threejs" in locals():
-        imp.reload(import_threejs)
-
-from bpy.props import *
-from bpy_extras.io_utils import ExportHelper, ImportHelper
-
-# ################################################################
-# Custom properties
-# ################################################################
-
-bpy.types.Object.THREE_castShadow = bpy.props.BoolProperty()
-bpy.types.Object.THREE_receiveShadow = bpy.props.BoolProperty()
-bpy.types.Object.THREE_doubleSided = bpy.props.BoolProperty()
-bpy.types.Object.THREE_exportGeometry = bpy.props.BoolProperty(default = True)
-
-bpy.types.Material.THREE_useVertexColors = bpy.props.BoolProperty()
-bpy.types.Material.THREE_depthWrite = bpy.props.BoolProperty(default = True)
-bpy.types.Material.THREE_depthTest = bpy.props.BoolProperty(default = True)
-
-THREE_material_types = [("Basic", "Basic", "Basic"), ("Phong", "Phong", "Phong"), ("Lambert", "Lambert", "Lambert")]
-bpy.types.Material.THREE_materialType = EnumProperty(name = "Material type", description = "Material type", items = THREE_material_types, default = "Lambert")
-
-THREE_blending_types = [("NoBlending", "NoBlending", "NoBlending"), ("NormalBlending", "NormalBlending", "NormalBlending"),
-                        ("AdditiveBlending", "AdditiveBlending", "AdditiveBlending"), ("SubtractiveBlending", "SubtractiveBlending", "SubtractiveBlending"),
-                        ("MultiplyBlending", "MultiplyBlending", "MultiplyBlending"), ("AdditiveAlphaBlending", "AdditiveAlphaBlending", "AdditiveAlphaBlending")]
-bpy.types.Material.THREE_blendingType = EnumProperty(name = "Blending type", description = "Blending type", items = THREE_blending_types, default = "NormalBlending")
-
-class OBJECT_PT_hello( bpy.types.Panel ):
-
-    bl_label = "THREE"
-    bl_space_type = "PROPERTIES"
-    bl_region_type = "WINDOW"
-    bl_context = "object"
-
-    def draw(self, context):
-        layout = self.layout
-        obj = context.object
-
-        row = layout.row()
-        row.label(text="Selected object: " + obj.name )
-
-        row = layout.row()
-        row.prop( obj, "THREE_exportGeometry", text="Export geometry" )
-
-        row = layout.row()
-        row.prop( obj, "THREE_castShadow", text="Casts shadow" )
-
-        row = layout.row()
-        row.prop( obj, "THREE_receiveShadow", text="Receives shadow" )
-
-        row = layout.row()
-        row.prop( obj, "THREE_doubleSided", text="Double sided" )
-
-class MATERIAL_PT_hello( bpy.types.Panel ):
-
-    bl_label = "THREE"
-    bl_space_type = "PROPERTIES"
-    bl_region_type = "WINDOW"
-    bl_context = "material"
-
-    def draw(self, context):
-        layout = self.layout
-        mat = context.material
-
-        row = layout.row()
-        row.label(text="Selected material: " + mat.name )
-
-        row = layout.row()
-        row.prop( mat, "THREE_materialType", text="Material type" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_blendingType", text="Blending type" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_useVertexColors", text="Use vertex colors" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_depthWrite", text="Enable depth writing" )
-
-        row = layout.row()
-        row.prop( mat, "THREE_depthTest", text="Enable depth testing" )
-
-
-# ################################################################
-# Importer
-# ################################################################
-
-class ImportTHREEJS(bpy.types.Operator, ImportHelper):
-    '''Load a Three.js ASCII JSON model'''
-
-    bl_idname = "import.threejs"
-    bl_label = "Import Three.js"
-
-    filename_ext = ".js"
-    filter_glob = StringProperty(default="*.js", options={'HIDDEN'})
-
-    option_flip_yz = BoolProperty(name="Flip YZ", description="Flip YZ", default=True)
-    recalculate_normals = BoolProperty(name="Recalculate normals", description="Recalculate vertex normals", default=True)
-    option_worker = BoolProperty(name="Worker", description="Old format using workers", default=False)
-
-    def execute(self, context):
-        import io_mesh_threejs.import_threejs
-        return io_mesh_threejs.import_threejs.load(self, context, **self.properties)
-
-
-    def draw(self, context):
-        layout = self.layout
-
-        row = layout.row()
-        row.prop(self.properties, "option_flip_yz")
-
-        row = layout.row()
-        row.prop(self.properties, "recalculate_normals")
-
-        row = layout.row()
-        row.prop(self.properties, "option_worker")
-
-
-# ################################################################
-# Exporter - settings
-# ################################################################
-
-SETTINGS_FILE_EXPORT = "threejs_settings_export.js"
-
-import os
-import json
-
-def file_exists(filename):
-    """Return true if file exists and 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_settings_fullpath():
-    return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT)
-
-def save_settings_export(properties):
-
-    settings = {
-    "option_export_scene" : properties.option_export_scene,
-    "option_embed_meshes" : properties.option_embed_meshes,
-    "option_url_base_html" : properties.option_url_base_html,
-    "option_copy_textures" : properties.option_copy_textures,
-
-    "option_lights" : properties.option_lights,
-    "option_cameras" : properties.option_cameras,
-
-    "option_animation_morph" : properties.option_animation_morph,
-    "option_animation_skeletal" : properties.option_animation_skeletal,
-
-    "option_frame_step" : properties.option_frame_step,
-    "option_all_meshes" : properties.option_all_meshes,
-
-    "option_flip_yz"      : properties.option_flip_yz,
-
-    "option_materials"       : properties.option_materials,
-    "option_normals"         : properties.option_normals,
-    "option_colors"          : properties.option_colors,
-    "option_uv_coords"       : properties.option_uv_coords,
-    "option_faces"           : properties.option_faces,
-    "option_vertices"        : properties.option_vertices,
-
-    "option_skinning"        : properties.option_skinning,
-    "option_bones"           : properties.option_bones,
-
-    "option_vertices_truncate" : properties.option_vertices_truncate,
-    "option_scale"        : properties.option_scale,
-
-    "align_model"         : properties.align_model
-    }
-
-    fname = get_settings_fullpath()
-    f = open(fname, "w")
-    json.dump(settings, f)
-
-def restore_settings_export(properties):
-
-    settings = {}
-
-    fname = get_settings_fullpath()
-    if file_exists(fname):
-        f = open(fname, "r")
-        settings = json.load(f)
-
-    properties.option_vertices = settings.get("option_vertices", True)
-    properties.option_vertices_truncate = settings.get("option_vertices_truncate", False)
-    properties.option_faces = settings.get("option_faces", True)
-    properties.option_normals = settings.get("option_normals", True)
-
-    properties.option_colors = settings.get("option_colors", True)
-    properties.option_uv_coords = settings.get("option_uv_coords", True)
-    properties.option_materials = settings.get("option_materials", True)
-
-    properties.option_skinning = settings.get("option_skinning", True)
-    properties.option_bones = settings.get("option_bones", True)
-
-    properties.align_model = settings.get("align_model", "None")
-
-    properties.option_scale = settings.get("option_scale", 1.0)
-    properties.option_flip_yz = settings.get("option_flip_yz", True)
-
-    properties.option_export_scene = settings.get("option_export_scene", False)
-    properties.option_embed_meshes = settings.get("option_embed_meshes", True)
-    properties.option_url_base_html = settings.get("option_url_base_html", False)
-    properties.option_copy_textures = settings.get("option_copy_textures", False)
-
-    properties.option_lights = settings.get("option_lights", False)
-    properties.option_cameras = settings.get("option_cameras", False)
-
-    properties.option_animation_morph = settings.get("option_animation_morph", False)
-    properties.option_animation_skeletal = settings.get("option_animation_skeletal", False)
-
-    properties.option_frame_step = settings.get("option_frame_step", 1)
-    properties.option_all_meshes = settings.get("option_all_meshes", True)
-
-# ################################################################
-# Exporter
-# ################################################################
-
-class ExportTHREEJS(bpy.types.Operator, ExportHelper):
-    '''Export selected object / scene for Three.js (ASCII JSON format).'''
-
-    bl_idname = "export.threejs"
-    bl_label = "Export Three.js"
-
-    filename_ext = ".js"
-
-    option_vertices = BoolProperty(name = "Vertices", description = "Export vertices", default = True)
-    option_vertices_deltas = BoolProperty(name = "Deltas", description = "Delta vertices", default = False)
-    option_vertices_truncate = BoolProperty(name = "Truncate", description = "Truncate vertices", default = False)
-
-    option_faces = BoolProperty(name = "Faces", description = "Export faces", default = True)
-    option_faces_deltas = BoolProperty(name = "Deltas", description = "Delta faces", default = False)
-
-    option_normals = BoolProperty(name = "Normals", description = "Export normals", default = True)
-
-    option_colors = BoolProperty(name = "Colors", description = "Export vertex colors", default = True)
-    option_uv_coords = BoolProperty(name = "UVs", description = "Export texture coordinates", default = True)
-    option_materials = BoolProperty(name = "Materials", description = "Export materials", default = True)
-
-    option_skinning = BoolProperty(name = "Skinning", description = "Export skin data", default = True)
-    option_bones = BoolProperty(name = "Bones", description = "Export bones", default = True)
-
-    align_types = [("None","None","None"), ("Center","Center","Center"), ("Bottom","Bottom","Bottom"), ("Top","Top","Top")]
-    align_model = EnumProperty(name = "Align model", description = "Align model", items = align_types, default = "None")
-
-    option_scale = FloatProperty(name = "Scale", description = "Scale vertices", min = 0.01, max = 1000.0, soft_min = 0.01, soft_max = 1000.0, default = 1.0)
-    option_flip_yz = BoolProperty(name = "Flip YZ", description = "Flip YZ", default = True)
-
-    option_export_scene = BoolProperty(name = "Scene", description = "Export scene", default = False)
-    option_embed_meshes = BoolProperty(name = "Embed meshes", description = "Embed meshes", default = True)
-    option_copy_textures = BoolProperty(name = "Copy textures", description = "Copy textures", default = False)
-    option_url_base_html = BoolProperty(name = "HTML as url base", description = "Use HTML as url base ", default = False)
-
-    option_lights = BoolProperty(name = "Lights", description = "Export default scene lights", default = False)
-    option_cameras = BoolProperty(name = "Cameras", description = "Export default scene cameras", default = False)
-
-    option_animation_morph = BoolProperty(name = "Morph animation", description = "Export animation (morphs)", default = False)
-    option_animation_skeletal = BoolProperty(name = "Skeletal animation", description = "Export animation (skeletal)", default = False)
-
-    option_frame_step = IntProperty(name = "Frame step", description = "Animation frame step", min = 1, max = 1000, soft_min = 1, soft_max = 1000, default = 1)
-    option_all_meshes = BoolProperty(name = "All meshes", description = "All meshes (merged)", default = True)
-
-    def invoke(self, context, event):
-        restore_settings_export(self.properties)
-        return ExportHelper.invoke(self, context, event)
-
-    @classmethod
-    def poll(cls, context):
-        return context.active_object != None
-
-    def execute(self, context):
-        print("Selected: " + context.active_object.name)
-
-        if not self.properties.filepath:
-            raise Exception("filename not set")
-
-        save_settings_export(self.properties)
-
-        filepath = self.filepath
-
-        import io_mesh_threejs.export_threejs
-        return io_mesh_threejs.export_threejs.save(self, context, **self.properties)
-
-    def draw(self, context):
-        layout = self.layout
-
-        row = layout.row()
-        row.label(text="Geometry:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_vertices")
-        # row = layout.row()
-        # row.enabled = self.properties.option_vertices
-        # row.prop(self.properties, "option_vertices_deltas")
-        row.prop(self.properties, "option_vertices_truncate")
-        layout.separator()
-
-        row = layout.row()
-        row.prop(self.properties, "option_faces")
-        row = layout.row()
-        row.enabled = self.properties.option_faces
-        # row.prop(self.properties, "option_faces_deltas")
-        layout.separator()
-
-        row = layout.row()
-        row.prop(self.properties, "option_normals")
-        layout.separator()
-
-        row = layout.row()
-        row.prop(self.properties, "option_bones")
-        row.prop(self.properties, "option_skinning")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Materials:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_uv_coords")
-        row.prop(self.properties, "option_colors")
-        row = layout.row()
-        row.prop(self.properties, "option_materials")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Settings:")
-
-        row = layout.row()
-        row.prop(self.properties, "align_model")
-        row = layout.row()
-        row.prop(self.properties, "option_flip_yz")
-        row.prop(self.properties, "option_scale")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="--------- Experimental ---------")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Scene:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_export_scene")
-        row.prop(self.properties, "option_embed_meshes")
-
-        row = layout.row()
-        row.prop(self.properties, "option_lights")
-        row.prop(self.properties, "option_cameras")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Animation:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_animation_morph")
-        row = layout.row()
-        row.prop(self.properties, "option_animation_skeletal")
-        row = layout.row()
-        row.prop(self.properties, "option_frame_step")
-        layout.separator()
-
-        row = layout.row()
-        row.label(text="Settings:")
-
-        row = layout.row()
-        row.prop(self.properties, "option_all_meshes")
-
-        row = layout.row()
-        row.prop(self.properties, "option_copy_textures")
-
-        row = layout.row()
-        row.prop(self.properties, "option_url_base_html")
-
-        layout.separator()
-
-
-# ################################################################
-# Common
-# ################################################################
-
-def menu_func_export(self, context):
-    default_path = bpy.data.filepath.replace(".blend", ".js")
-    self.layout.operator(ExportTHREEJS.bl_idname, text="Three.js (.js)").filepath = default_path
-
-def menu_func_import(self, context):
-    self.layout.operator(ImportTHREEJS.bl_idname, text="Three.js (.js)")
-
-def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.INFO_MT_file_export.append(menu_func_export)
-    bpy.types.INFO_MT_file_import.append(menu_func_import)
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    bpy.types.INFO_MT_file_export.remove(menu_func_export)
-    bpy.types.INFO_MT_file_import.remove(menu_func_import)
-
-if __name__ == "__main__":
-    register()

+ 0 - 2409
utils/exporters/blender/2.64/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -1,2409 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-"""
-Blender exporter for Three.js (ASCII JSON format).
-
-TODO
-    - binary format
-"""
-
-import bpy
-import mathutils
-
-import shutil
-import os
-import os.path
-import math
-import operator
-import random
-
-# #####################################################
-# Configuration
-# #####################################################
-
-DEFAULTS = {
-"bgcolor" : [0, 0, 0],
-"bgalpha" : 1.0,
-
-"position" : [0, 0, 0],
-"rotation" : [-math.pi/2, 0, 0],
-"scale"    : [1, 1, 1],
-
-"camera"  :
-    {
-        "name" : "default_camera",
-        "type" : "PerspectiveCamera",
-        "near" : 1,
-        "far"  : 10000,
-        "fov"  : 60,
-        "aspect": 1.333,
-        "position" : [0, 0, 10],
-        "target"   : [0, 0, 0]
-    },
-
-"light" :
- {
-    "name"       : "default_light",
-    "type"       : "DirectionalLight",
-    "direction"  : [0, 1, 1],
-    "color"      : [1, 1, 1],
-    "intensity"  : 0.8
- }
-}
-
-# 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]
-
-
-# skinning
-MAX_INFLUENCES = 2
-
-
-# #####################################################
-# Templates - scene
-# #####################################################
-
-TEMPLATE_SCENE_ASCII = """\
-{
-
-"metadata" :
-{
-	"formatVersion" : 3.2,
-	"type" 			: "scene",
-	"sourceFile"    : "%(fname)s",
-	"generatedBy"   : "Blender 2.64 Exporter",
-	"objects"       : %(nobjects)s,
-	"geometries"    : %(ngeometries)s,
-	"materials"     : %(nmaterials)s,
-	"textures"      : %(ntextures)s
-},
-
-"urlBaseType" : %(basetype)s,
-
-%(sections)s
-
-"transform" :
-{
-	"position"  : %(position)s,
-	"rotation"  : %(rotation)s,
-	"scale"     : %(scale)s
-},
-
-"defaults" :
-{
-	"bgcolor" : %(bgcolor)s,
-	"bgalpha" : %(bgalpha)f,
-	"camera"  : %(defcamera)s
-}
-
-}
-"""
-
-TEMPLATE_SECTION = """
-"%s" :
-{
-%s
-},
-"""
-
-TEMPLATE_OBJECT = """\
-	%(object_id)s : {
-		"geometry"  : %(geometry_id)s,
-		"groups"    : [ %(group_id)s ],
-		"material"  : %(material_id)s,
-		"position"  : %(position)s,
-		"rotation"  : %(rotation)s,
-		"quaternion": %(quaternion)s,
-		"scale"     : %(scale)s,
-		"visible"       : %(visible)s,
-		"castShadow"    : %(castShadow)s,
-		"receiveShadow" : %(receiveShadow)s,
-		"doubleSided"   : %(doubleSided)s
-	}"""
-
-TEMPLATE_EMPTY = """\
-	%(object_id)s : {
-		"groups"    : [ %(group_id)s ],
-		"position"  : %(position)s,
-		"rotation"  : %(rotation)s,
-		"quaternion": %(quaternion)s,
-		"scale"     : %(scale)s
-	}"""
-
-TEMPLATE_GEOMETRY_LINK = """\
-	%(geometry_id)s : {
-		"type" : "ascii",
-		"url"  : %(model_file)s
-	}"""
-
-TEMPLATE_GEOMETRY_EMBED = """\
-	%(geometry_id)s : {
-		"type" : "embedded",
-		"id"  : %(embed_id)s
-	}"""
-
-TEMPLATE_TEXTURE = """\
-	%(texture_id)s : {
-		"url": %(texture_file)s%(extras)s
-	}"""
-
-TEMPLATE_MATERIAL_SCENE = """\
-	%(material_id)s : {
-		"type": %(type)s,
-		"parameters": { %(parameters)s }
-	}"""
-
-TEMPLATE_CAMERA_PERSPECTIVE = """\
-	%(camera_id)s : {
-		"type"  : "PerspectiveCamera",
-		"fov"   : %(fov)f,
-		"aspect": %(aspect)f,
-		"near"  : %(near)f,
-		"far"   : %(far)f,
-		"position": %(position)s,
-		"target"  : %(target)s
-	}"""
-
-TEMPLATE_CAMERA_ORTHO = """\
-	%(camera_id)s : {
-		"type"  : "OrthographicCamera",
-		"left"  : %(left)f,
-		"right" : %(right)f,
-		"top"   : %(top)f,
-		"bottom": %(bottom)f,
-		"near"  : %(near)f,
-		"far"   : %(far)f,
-		"position": %(position)s,
-		"target"  : %(target)s
-	}"""
-
-TEMPLATE_LIGHT_DIRECTIONAL = """\
-	%(light_id)s : {
-		"type"       : "DirectionalLight",
-		"direction"  : %(direction)s,
-		"color"      : %(color)d,
-		"intensity"  : %(intensity).2f
-	}"""
-
-TEMPLATE_LIGHT_POINT = """\
-	%(light_id)s : {
-		"type"       : "PointLight",
-		"position"   : %(position)s,
-		"color"      : %(color)d,
-		"intensity"  : %(intensity).3f
-	}"""
-
-TEMPLATE_VEC4 = '[ %g, %g, %g, %g ]'
-TEMPLATE_VEC3 = '[ %g, %g, %g ]'
-TEMPLATE_VEC2 = '[ %g, %g ]'
-TEMPLATE_STRING = '"%s"'
-TEMPLATE_HEX = "0x%06x"
-
-# #####################################################
-# Templates - model
-# #####################################################
-
-TEMPLATE_FILE_ASCII = """\
-{
-
-	"metadata" :
-	{
-		"formatVersion" : 3.1,
-		"generatedBy"   : "Blender 2.64 Exporter",
-		"vertices"      : %(nvertex)d,
-		"faces"         : %(nface)d,
-		"normals"       : %(nnormal)d,
-		"colors"        : %(ncolor)d,
-		"uvs"           : [%(nuvs)s],
-		"materials"     : %(nmaterial)d,
-		"morphTargets"  : %(nmorphTarget)d,
-		"bones"         : %(nbone)d
-	},
-
-%(model)s
-
-}
-"""
-
-TEMPLATE_MODEL_ASCII = """\
-	"scale" : %(scale)f,
-
-	"materials" : [%(materials)s],
-
-	"vertices" : [%(vertices)s],
-
-	"morphTargets" : [%(morphTargets)s],
-
-	"normals" : [%(normals)s],
-
-	"colors" : [%(colors)s],
-
-	"uvs" : [%(uvs)s],
-
-	"faces" : [%(faces)s],
-
-	"bones" : [%(bones)s],
-
-	"skinIndices" : [%(indices)s],
-
-	"skinWeights" : [%(weights)s],
-
-	"animation" : {%(animation)s}
-"""
-
-TEMPLATE_VERTEX = "%g,%g,%g"
-TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d"
-
-TEMPLATE_N = "%g,%g,%g"
-TEMPLATE_UV = "%g,%g"
-TEMPLATE_C = "%d"
-
-# #####################################################
-# Utils
-# #####################################################
-
-def veckey3(x,y,z):
-    return round(x, 6), round(y, 6), round(z, 6)
-
-def veckey3d(v):
-    return veckey3(v.x, v.y, v.z)
-
-def veckey2d(v):
-    return round(v[0], 6), round(v[1], 6)
-
-def get_faces(obj):
-    if hasattr(obj, "tessfaces"):
-        return obj.tessfaces
-    else:
-        return obj.faces
-
-def get_normal_indices(v, normals, mesh):
-    n = []
-    mv = mesh.vertices
-
-    for i in v:
-        normal = mv[i].normal
-        key = veckey3d(normal)
-
-        n.append( normals[key] )
-
-    return n
-
-def get_uv_indices(face_index, uvs, mesh, layer_index):
-    uv = []
-    uv_layer = mesh.tessface_uv_textures[layer_index].data
-    for i in uv_layer[face_index].uv:
-        uv.append( uvs[veckey2d(i)] )
-    return uv
-
-def get_color_indices(face_index, colors, mesh):
-    c = []
-    color_layer = mesh.tessface_vertex_colors.active.data
-    face_colors = color_layer[face_index]
-    face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-    for i in face_colors:
-        c.append( colors[hexcolor(i)] )
-    return c
-
-def rgb2int(rgb):
-    color = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255);
-    return color
-
-# #####################################################
-# Utils - files
-# #####################################################
-
-def write_file(fname, content):
-    out = open(fname, "w")
-    out.write(content)
-    out.close()
-
-def ensure_folder_exist(foldername):
-    """Create folder (with whole path) if it doesn't exist yet."""
-
-    if not os.access(foldername, os.R_OK|os.W_OK|os.X_OK):
-        os.makedirs(foldername)
-
-def ensure_extension(filepath, extension):
-    if not filepath.lower().endswith(extension):
-        filepath += extension
-    return filepath
-
-def generate_mesh_filename(meshname, filepath):
-    normpath = os.path.normpath(filepath)
-    path, ext = os.path.splitext(normpath)
-    return "%s.%s%s" % (path, meshname, ext)
-
-
-# #####################################################
-# Utils - alignment
-# #####################################################
-
-def bbox(vertices):
-    """Compute bounding box of vertex array.
-    """
-
-    if len(vertices)>0:
-        minx = maxx = vertices[0].co.x
-        miny = maxy = vertices[0].co.y
-        minz = maxz = vertices[0].co.z
-
-        for v in vertices[1:]:
-            if v.co.x < minx:
-                minx = v.co.x
-            elif v.co.x > maxx:
-                maxx = v.co.x
-
-            if v.co.y < miny:
-                miny = v.co.y
-            elif v.co.y > maxy:
-                maxy = v.co.y
-
-            if v.co.z < minz:
-                minz = v.co.z
-            elif v.co.z > maxz:
-                maxz = v.co.z
-
-        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 range(len(vertices)):
-        vertices[i].co.x += t[0]
-        vertices[i].co.y += t[1]
-        vertices[i].co.z += t[2]
-
-def center(vertices):
-    """Center model (middle of bounding box).
-    """
-
-    bb = bbox(vertices)
-
-    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
-    cy = bb['y'][0] + (bb['y'][1] - bb['y'][0])/2.0
-    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
-
-    translate(vertices, [-cx,-cy,-cz])
-
-    return [-cx,-cy,-cz]
-
-def top(vertices):
-    """Align top of the model with the floor (Y-axis) and center it around X and Z.
-    """
-
-    bb = bbox(vertices)
-
-    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
-    cy = bb['y'][1]
-    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
-
-    translate(vertices, [-cx,-cy,-cz])
-
-    return [-cx,-cy,-cz]
-
-def bottom(vertices):
-    """Align bottom of the model with the floor (Y-axis) and center it around X and Z.
-    """
-
-    bb = bbox(vertices)
-
-    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
-    cy = bb['y'][0]
-    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
-
-    translate(vertices, [-cx,-cy,-cz])
-
-    return [-cx,-cy,-cz]
-
-# #####################################################
-# Elements rendering
-# #####################################################
-
-def hexcolor(c):
-    return ( int(c[0] * 255) << 16  ) + ( int(c[1] * 255) << 8 ) + int(c[2] * 255)
-
-def generate_vertices(vertices, option_vertices_truncate, option_vertices):
-    if not option_vertices:
-        return ""
-
-    return ",".join(generate_vertex(v, option_vertices_truncate) for v in vertices)
-
-def generate_vertex(v, option_vertices_truncate):
-    if not option_vertices_truncate:
-        return TEMPLATE_VERTEX % (v.co.x, v.co.y, v.co.z)
-    else:
-        return TEMPLATE_VERTEX_TRUNCATE % (v.co.x, v.co.y, v.co.z)
-
-def generate_normal(n):
-    return TEMPLATE_N % (n[0], n[1], n[2])
-
-def generate_vertex_color(c):
-    return TEMPLATE_C % c
-
-def generate_uv(uv):
-    return TEMPLATE_UV % (uv[0], uv[1])
-
-# #####################################################
-# Model exporter - faces
-# #####################################################
-
-def setBit(value, position, on):
-    if on:
-        mask = 1 << position
-        return (value | mask)
-    else:
-        mask = ~(1 << position)
-        return (value & mask)
-
-def generate_faces(normals, uv_layers, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces):
-
-    if not option_faces:
-        return "", 0
-
-    vertex_offset = 0
-    material_offset = 0
-
-    chunks = []
-    for mesh, object in meshes:
-
-        vertexUV = len(mesh.uv_textures) > 0
-        vertexColors = len(mesh.vertex_colors) > 0
-
-        mesh_colors = option_colors and vertexColors
-        mesh_uvs = option_uv_coords and vertexUV
-
-        if vertexUV:
-            active_uv_layer = mesh.uv_textures.active
-            if not active_uv_layer:
-                mesh_extract_uvs = False
-
-        if vertexColors:
-            active_col_layer = mesh.vertex_colors.active
-            if not active_col_layer:
-                mesh_extract_colors = False
-
-        for i, f in enumerate(get_faces(mesh)):
-            face = generate_face(f, i, normals, uv_layers, colors, mesh, option_normals, mesh_colors, mesh_uvs, option_materials, vertex_offset, material_offset)
-            chunks.append(face)
-
-        vertex_offset += len(mesh.vertices)
-
-        material_count = len(mesh.materials)
-        if material_count == 0:
-            material_count = 1
-
-        material_offset += material_count
-
-    return ",".join(chunks), len(chunks)
-
-def generate_face(f, faceIndex, normals, uv_layers, colors, mesh, option_normals, option_colors, option_uv_coords, option_materials, vertex_offset, material_offset):
-    isTriangle = ( len(f.vertices) == 3 )
-
-    if isTriangle:
-        nVertices = 3
-    else:
-        nVertices = 4
-
-    hasMaterial = option_materials
-
-    hasFaceUvs = False # not supported in Blender
-    hasFaceVertexUvs = option_uv_coords
-
-    hasFaceNormals = False # don't export any face normals (as they are computed in engine)
-    hasFaceVertexNormals = option_normals
-
-    hasFaceColors = False       # not supported in Blender
-    hasFaceVertexColors = option_colors
-
-    faceType = 0
-    faceType = setBit(faceType, 0, not isTriangle)
-    faceType = setBit(faceType, 1, hasMaterial)
-    faceType = setBit(faceType, 2, hasFaceUvs)
-    faceType = setBit(faceType, 3, hasFaceVertexUvs)
-    faceType = setBit(faceType, 4, hasFaceNormals)
-    faceType = setBit(faceType, 5, hasFaceVertexNormals)
-    faceType = setBit(faceType, 6, hasFaceColors)
-    faceType = setBit(faceType, 7, hasFaceVertexColors)
-
-    faceData = []
-
-    # order is important, must match order in JSONLoader
-
-    # face type
-    # vertex indices
-    # material index
-    # face uvs index
-    # face vertex uvs indices
-    # face color index
-    # face vertex colors indices
-
-    faceData.append(faceType)
-
-    # must clamp in case on polygons bigger than quads
-
-    for i in range(nVertices):
-        index = f.vertices[i] + vertex_offset
-        faceData.append(index)
-
-    if hasMaterial:
-        index = f.material_index + material_offset
-        faceData.append( index )
-
-    if hasFaceVertexUvs:
-        for layer_index, uvs in enumerate(uv_layers):
-            uv = get_uv_indices(faceIndex, uvs, mesh, layer_index)
-            for i in range(nVertices):
-                index = uv[i]
-                faceData.append(index)
-
-    if hasFaceVertexNormals:
-        n = get_normal_indices(f.vertices, normals, mesh)
-        for i in range(nVertices):
-            index = n[i]
-            faceData.append(index)
-
-    if hasFaceVertexColors:
-        c = get_color_indices(faceIndex, colors, mesh)
-        for i in range(nVertices):
-            index = c[i]
-            faceData.append(index)
-
-    return ",".join( map(str, faceData) )
-
-
-# #####################################################
-# Model exporter - normals
-# #####################################################
-
-def extract_vertex_normals(mesh, normals, count):
-    for f in get_faces(mesh):
-        for v in f.vertices:
-
-            normal = mesh.vertices[v].normal
-            key = veckey3d(normal)
-
-            if key not in normals:
-                normals[key] = count
-                count += 1
-
-    return count
-
-def generate_normals(normals, option_normals):
-    if not option_normals:
-        return ""
-
-    chunks = []
-    for key, index in sorted(normals.items(), key = operator.itemgetter(1)):
-        chunks.append(key)
-
-    return ",".join(generate_normal(n) for n in chunks)
-
-# #####################################################
-# Model exporter - vertex colors
-# #####################################################
-
-def extract_vertex_colors(mesh, colors, count):
-    color_layer = mesh.tessface_vertex_colors.active.data
-
-    for face_index, face in enumerate(get_faces(mesh)):
-
-        face_colors = color_layer[face_index]
-        face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-
-        for c in face_colors:
-            key = hexcolor(c)
-            if key not in colors:
-                colors[key] = count
-                count += 1
-
-    return count
-
-def generate_vertex_colors(colors, option_colors):
-    if not option_colors:
-        return ""
-
-    chunks = []
-    for key, index in sorted(colors.items(), key=operator.itemgetter(1)):
-        chunks.append(key)
-
-    return ",".join(generate_vertex_color(c) for c in chunks)
-
-# #####################################################
-# Model exporter - UVs
-# #####################################################
-
-def extract_uvs(mesh, uv_layers, counts):
-    for index, layer in enumerate(mesh.tessface_uv_textures):
-
-        if len(uv_layers) <= index:
-            uvs = {}
-            count = 0
-            uv_layers.append(uvs)
-            counts.append(count)
-        else:
-            uvs = uv_layers[index]
-            count = counts[index]
-
-        uv_layer = layer.data
-
-        for face_index, face in enumerate(get_faces(mesh)):
-
-            for uv_index, uv in enumerate(uv_layer[face_index].uv):
-
-                key = veckey2d(uv)
-                if key not in uvs:
-                    uvs[key] = count
-                    count += 1
-
-        counts[index] = count
-
-    return counts
-
-def generate_uvs(uv_layers, option_uv_coords):
-    if not option_uv_coords:
-        return "[]"
-
-    layers = []
-    for uvs in uv_layers:
-        chunks = []
-        for key, index in sorted(uvs.items(), key=operator.itemgetter(1)):
-            chunks.append(key)
-        layer = ",".join(generate_uv(n) for n in chunks)
-        layers.append(layer)
-
-    return ",".join("[%s]" % n for n in layers)
-
-# ##############################################################################
-# Model exporter - bones
-# (only the first armature will exported)
-# ##############################################################################
-
-def generate_bones(option_bones, flipyz):
-
-    if not option_bones or len(bpy.data.armatures) == 0:
-        return "", 0
-
-    hierarchy = []
-
-    armature = bpy.data.armatures[0]
-
-    TEMPLATE_BONE = '{"parent":%d,"name":"%s","pos":[%g,%g,%g],"rotq":[0,0,0,1]}'
-
-    for bone in armature.bones:
-        if bone.parent == None:
-            if flipyz:
-                joint = TEMPLATE_BONE % (-1, bone.name, bone.head.x, bone.head.z, -bone.head.y)
-                hierarchy.append(joint)
-            else:
-                joint = TEMPLATE_BONE % (-1, bone.name, bone.head.x, bone.head.y, bone.head.z)
-                hierarchy.append(joint)
-        else:
-            index = i = 0
-            for parent in armature.bones:
-                if parent.name == bone.parent.name:
-                    index = i
-                i += 1
-
-            position = bone.head_local - bone.parent.head_local
-
-            if flipyz:
-                joint = TEMPLATE_BONE % (index, bone.name, position.x, position.z, -position.y)
-                hierarchy.append(joint)
-            else:
-                joint = TEMPLATE_BONE % (index, bone.name, position.x, position.y, position.z)
-                hierarchy.append(joint)
-
-    bones_string = ",".join(hierarchy)
-
-    return bones_string, len(armature.bones)
-
-
-# ##############################################################################
-# Model exporter - skin indices and weights
-# ##############################################################################
-
-def generate_indices_and_weights(meshes, option_skinning):
-
-    if not option_skinning or len(bpy.data.armatures) == 0:
-        return "", ""
-
-    indices = []
-    weights = []
-
-    armature = bpy.data.armatures[0]
-
-    for mesh, object in meshes:
-
-        i = 0
-        mesh_index = -1
-
-        # find the original object
-
-        for obj in bpy.data.objects:
-            if obj.name == mesh.name or obj == object:
-                mesh_index = i
-            i += 1
-
-        if mesh_index == -1:
-            print("generate_indices: couldn't find object for mesh", mesh.name)
-            continue
-
-        object = bpy.data.objects[mesh_index]
-
-        for vertex in mesh.vertices:
-
-            # sort bones by influence
-
-            bone_array = []
-
-            for group in vertex.groups:
-                index = group.group
-                weight = group.weight
-
-                bone_array.append( (index, weight) )
-
-            bone_array.sort(key = operator.itemgetter(1), reverse=True)
-
-            # select first N bones
-
-            for i in range(MAX_INFLUENCES):
-
-                if i < len(bone_array):
-                    bone_proxy = bone_array[i]
-
-                    index = bone_proxy[0]
-                    weight = bone_proxy[1]
-
-                    for j, bone in enumerate(armature.bones):
-                        if object.vertex_groups[index].name == bone.name:
-                            indices.append('%d' % j)
-                            weights.append('%g' % weight)
-                            break
-
-                else:
-                    indices.append('0')
-                    weights.append('0')
-
-
-    indices_string = ",".join(indices)
-    weights_string = ",".join(weights)
-
-    return indices_string, weights_string
-
-
-# ##############################################################################
-# Model exporter - skeletal animation
-# (only the first action will exported)
-# ##############################################################################
-
-def generate_animation(option_animation_skeletal, option_frame_step, flipyz):
-
-    if not option_animation_skeletal or len(bpy.data.actions) == 0 or len(bpy.data.armatures) == 0:
-        return ""
-
-    # TODO: Add scaling influences
-
-    action = bpy.data.actions[0]
-    armature = bpy.data.armatures[0]
-
-    parents = []
-    parent_index = -1
-
-    fps = bpy.data.scenes[0].render.fps
-
-    end_frame = action.frame_range[1]
-    start_frame = action.frame_range[0]
-
-    frame_length = end_frame - start_frame
-
-    TEMPLATE_KEYFRAME_FULL  = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g],"scl":[1,1,1]}'
-    TEMPLATE_KEYFRAME       = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g]}'
-    TEMPLATE_KEYFRAME_POS   = '{"time":%g,"pos":[%g,%g,%g]}'
-    TEMPLATE_KEYFRAME_ROT   = '{"time":%g,"rot":[%g,%g,%g,%g]}'
-
-    for hierarchy in armature.bones:
-
-        keys = []
-
-        for frame in range(int(start_frame), int(end_frame / option_frame_step) + 1):
-
-            pos, pchange = position(hierarchy, frame * option_frame_step)
-            rot, rchange = rotation(hierarchy, frame * option_frame_step)
-
-            if flipyz:
-                px, py, pz = pos.x, pos.z, -pos.y
-                rx, ry, rz, rw = rot.x, rot.z, -rot.y, rot.w
-            else:
-                px, py, pz = pos.x, pos.y, pos.z
-                rx, ry, rz, rw = rot.x, rot.y, rot.z, rot.w
-
-            # START-FRAME: needs pos, rot and scl attributes (required frame)
-
-            if frame == int(start_frame):
-
-                time = (frame * option_frame_step - start_frame) / fps
-                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw)
-                keys.append(keyframe)
-
-            # END-FRAME: needs pos, rot and scl attributes with animation length (required frame)
-
-            elif frame == int(end_frame / option_frame_step):
-
-                time = frame_length / fps
-                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw)
-                keys.append(keyframe)
-
-            # MIDDLE-FRAME: needs only one of the attributes, can be an empty frame (optional frame)
-
-            elif pchange == True or rchange == True:
-
-                time = (frame * option_frame_step - start_frame) / fps
-
-                if pchange == True and rchange == True:
-                    keyframe = TEMPLATE_KEYFRAME % (time, px, py, pz, rx, ry, rz, rw)
-                elif pchange == True:
-                    keyframe = TEMPLATE_KEYFRAME_POS % (time, px, py, pz)
-                elif rchange == True:
-                    keyframe = TEMPLATE_KEYFRAME_ROT % (time, rx, ry, rz, rw)
-
-                keys.append(keyframe)
-
-        keys_string = ",".join(keys)
-        parent = '{"parent":%d,"keys":[%s]}' % (parent_index, keys_string)
-        parent_index += 1
-        parents.append(parent)
-
-    hierarchy_string = ",".join(parents)
-    animation_string = '"name":"%s","fps":%d,"length":%g,"hierarchy":[%s]' % (action.name, fps, (frame_length / fps), hierarchy_string)
-
-    return animation_string
-
-def handle_position_channel(channel, frame, position):
-
-    change = False
-
-    if channel.array_index in [0, 1, 2]:
-        for keyframe in channel.keyframe_points:
-            if keyframe.co[0] == frame:
-                change = True
-
-        value = channel.evaluate(frame)
-
-        if channel.array_index == 0:
-            position.x = value
-
-        if channel.array_index == 1:
-            position.y = value
-
-        if channel.array_index == 2:
-            position.z = value
-
-    return change
-
-def position(bone, frame):
-
-    position = mathutils.Vector((0,0,0))
-    change = False
-
-    action = bpy.data.actions[0]
-    ngroups = len(action.groups)
-
-
-
-    if ngroups > 0:
-
-        index = 0
-
-        for i in range(ngroups):
-            if action.groups[i].name == bone.name:
-                index = i
-
-        for channel in action.groups[index].channels:
-            if "location" in channel.data_path:
-                hasChanged = handle_position_channel(channel, frame, position)
-                change = change or hasChanged
-
-    else:
-
-        bone_label = '"%s"' % bone.name
-
-        for channel in action.fcurves:
-            data_path = channel.data_path
-            if bone_label in data_path and "location" in data_path:
-                hasChanged = handle_position_channel(channel, frame, position)
-                change = change or hasChanged
-
-    position = position * bone.matrix_local.inverted()
-
-    if bone.parent == None:
-
-        position.x += bone.head.x
-        position.y += bone.head.y
-        position.z += bone.head.z
-
-    else:
-
-        parent = bone.parent
-
-        parentInvertedLocalMatrix = parent.matrix_local.inverted()
-        parentHeadTailDiff = parent.tail_local - parent.head_local
-
-        position.x += (bone.head * parentInvertedLocalMatrix).x + parentHeadTailDiff.x
-        position.y += (bone.head * parentInvertedLocalMatrix).y + parentHeadTailDiff.y
-        position.z += (bone.head * parentInvertedLocalMatrix).z + parentHeadTailDiff.z
-
-    return position, change
-
-def handle_rotation_channel(channel, frame, rotation):
-
-    change = False
-
-    if channel.array_index in [0, 1, 2, 3]:
-
-        for keyframe in channel.keyframe_points:
-            if keyframe.co[0] == frame:
-                change = True
-
-        value = channel.evaluate(frame)
-
-        if channel.array_index == 1:
-            rotation.x = value
-
-        elif channel.array_index == 2:
-            rotation.y = value
-
-        elif channel.array_index == 3:
-            rotation.z = value
-
-        elif channel.array_index == 0:
-            rotation.w = value
-
-    return change
-
-def rotation(bone, frame):
-
-    # TODO: calculate rotation also from rotation_euler channels
-
-    rotation = mathutils.Vector((0,0,0,1))
-
-    change = False
-
-    action = bpy.data.actions[0]
-    ngroups = len(action.groups)
-
-    # animation grouped by bones
-
-    if ngroups > 0:
-
-        index = 0
-
-        for i in range(ngroups):
-            if action.groups[i].name == bone.name:
-                index = i
-
-        for channel in action.groups[index].channels:
-            if "quaternion" in channel.data_path:
-                hasChanged = handle_rotation_channel(channel, frame, rotation)
-                change = change or hasChanged
-
-    # animation in raw fcurves
-
-    else:
-
-        bone_label = '"%s"' % bone.name
-
-        for channel in action.fcurves:
-            data_path = channel.data_path
-            if bone_label in data_path and "quaternion" in data_path:
-                hasChanged = handle_rotation_channel(channel, frame, rotation)
-                change = change or hasChanged
-
-    rot3 = rotation.to_3d()
-    rotation.xyz = rot3 * bone.matrix_local.inverted()
-
-    return rotation, change
-
-# #####################################################
-# Model exporter - materials
-# #####################################################
-
-def generate_color(i):
-    """Generate hex color corresponding to integer.
-
-    Colors should have well defined ordering.
-    First N colors are hardcoded, then colors are random
-    (must seed random number  generator with deterministic value
-    before getting colors).
-    """
-
-    if i < len(COLORS):
-        #return "0x%06x" % COLORS[i]
-        return COLORS[i]
-    else:
-        #return "0x%06x" % int(0xffffff * random.random())
-        return int(0xffffff * random.random())
-
-def generate_mtl(materials):
-    """Generate dummy materials.
-    """
-
-    mtl = {}
-    for m in materials:
-        index = materials[m]
-        mtl[m] = {
-            "DbgName": m,
-            "DbgIndex": index,
-            "DbgColor": generate_color(index),
-            "vertexColors" : False
-        }
-    return mtl
-
-def value2string(v):
-    if type(v) == str and v[0:2] != "0x":
-        return '"%s"' % v
-    elif type(v) == bool:
-        return str(v).lower()
-    elif type(v) == list:
-        return "[%s]" % (", ".join(value2string(x) for x in v))
-    return str(v)
-
-def generate_materials(mtl, materials, draw_type):
-    """Generate JS array of materials objects
-    """
-
-    mtl_array = []
-    for m in mtl:
-        index = materials[m]
-
-        # add debug information
-        #  materials should be sorted according to how
-        #  they appeared in OBJ file (for the first time)
-        #  this index is identifier used in face definitions
-        mtl[m]['DbgName'] = m
-        mtl[m]['DbgIndex'] = index
-        mtl[m]['DbgColor'] = generate_color(index)
-
-        if draw_type in [ "BOUNDS", "WIRE" ]:
-            mtl[m]['wireframe'] = True
-            mtl[m]['DbgColor'] = 0xff0000
-
-        mtl_raw = ",\n".join(['\t\t"%s" : %s' % (n, value2string(v)) for n,v in sorted(mtl[m].items())])
-        mtl_string = "\t{\n%s\n\t}" % mtl_raw
-        mtl_array.append([index, mtl_string])
-
-    return ",\n\n".join([m for i,m in sorted(mtl_array)]), len(mtl_array)
-
-def extract_materials(mesh, scene, option_colors, option_copy_textures, filepath):
-    world = scene.world
-
-    materials = {}
-    for m in mesh.materials:
-        if m:
-            materials[m.name] = {}
-            material = materials[m.name]
-
-            material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
-                                        m.diffuse_intensity * m.diffuse_color[1],
-                                        m.diffuse_intensity * m.diffuse_color[2]]
-
-            material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
-                                         m.specular_intensity * m.specular_color[1],
-                                         m.specular_intensity * m.specular_color[2]]
-
-            material['colorAmbient'] = [m.ambient * material['colorDiffuse'][0],
-                                        m.ambient * material['colorDiffuse'][1],
-                                        m.ambient * material['colorDiffuse'][2]]
-
-            material['transparency'] = m.alpha
-
-            # not sure about mapping values to Blinn-Phong shader
-            # Blender uses INT from [1, 511] with default 0
-            # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
-
-            material["specularCoef"] = m.specular_hardness
-
-            textures = guess_material_textures(m)
-
-            handle_texture('diffuse', textures, material, filepath, option_copy_textures)
-            handle_texture('light', textures, material, filepath, option_copy_textures)
-            handle_texture('normal', textures, material, filepath, option_copy_textures)
-            handle_texture('specular', textures, material, filepath, option_copy_textures)
-            handle_texture('bump', textures, material, filepath, option_copy_textures)
-
-            material["vertexColors"] = m.THREE_useVertexColors and option_colors
-
-            # can't really use this reliably to tell apart Phong from Lambert
-            # as Blender defaults to non-zero specular color
-            #if m.specular_intensity > 0.0 and (m.specular_color[0] > 0 or m.specular_color[1] > 0 or m.specular_color[2] > 0):
-            #    material['shading'] = "Phong"
-            #else:
-            #    material['shading'] = "Lambert"
-
-            if textures['normal']:
-                material['shading'] = "Phong"
-            else:
-                material['shading'] = m.THREE_materialType
-
-            material['blending'] = m.THREE_blendingType
-            material['depthWrite'] = m.THREE_depthWrite
-            material['depthTest'] = m.THREE_depthTest
-            material['transparent'] = m.use_transparency
-
-    return materials
-
-def generate_materials_string(mesh, scene, option_colors, draw_type, option_copy_textures, filepath, offset):
-
-    random.seed(42) # to get well defined color order for debug materials
-
-    materials = {}
-    if mesh.materials:
-        for i, m in enumerate(mesh.materials):
-            mat_id = i + offset
-            if m:
-                materials[m.name] = mat_id
-            else:
-                materials["undefined_dummy_%0d" % mat_id] = mat_id
-
-
-    if not materials:
-        materials = { 'default': 0 }
-
-    # default dummy materials
-
-    mtl = generate_mtl(materials)
-
-    # extract real materials from the mesh
-
-    mtl.update(extract_materials(mesh, scene, option_colors, option_copy_textures, filepath))
-
-    return generate_materials(mtl, materials, draw_type)
-
-def handle_texture(id, textures, material, filepath, option_copy_textures):
-
-    if textures[id]:
-        texName     = 'map%s'       % id.capitalize()
-        repeatName  = 'map%sRepeat' % id.capitalize()
-        wrapName    = 'map%sWrap'   % id.capitalize()
-
-        slot = textures[id]['slot']
-        texture = textures[id]['texture']
-        image = texture.image
-        fname = extract_texture_filename(image)
-        material[texName] = fname
-
-        if option_copy_textures:
-            save_image(image, fname, filepath)
-
-        if texture.repeat_x != 1 or texture.repeat_y != 1:
-            material[repeatName] = [texture.repeat_x, texture.repeat_y]
-
-        if texture.extension == "REPEAT":
-            wrap_x = "repeat"
-            wrap_y = "repeat"
-
-            if texture.use_mirror_x:
-                wrap_x = "mirror"
-            if texture.use_mirror_y:
-                wrap_y = "mirror"
-
-            material[wrapName] = [wrap_x, wrap_y]
-
-        if slot.use_map_normal:
-            if slot.normal_factor != 1.0:
-                if id == "bump":
-                    material['mapBumpScale'] = slot.normal_factor
-                else:
-                    material['mapNormalFactor'] = slot.normal_factor
-
-
-# #####################################################
-# ASCII model generator
-# #####################################################
-
-def generate_ascii_model(meshes, morphs,
-                         scene,
-                         option_vertices,
-                         option_vertices_truncate,
-                         option_faces,
-                         option_normals,
-                         option_uv_coords,
-                         option_materials,
-                         option_colors,
-                         option_bones,
-                         option_skinning,
-                         align_model,
-                         flipyz,
-                         option_scale,
-                         option_copy_textures,
-                         filepath,
-                         option_animation_morph,
-                         option_animation_skeletal,
-                         option_frame_step):
-
-    vertices = []
-
-    vertex_offset = 0
-    vertex_offsets = []
-
-    nnormal = 0
-    normals = {}
-
-    ncolor = 0
-    colors = {}
-
-    nuvs = []
-    uv_layers = []
-
-    nmaterial = 0
-    materials = []
-
-    for mesh, object in meshes:
-
-        vertexUV = len(mesh.uv_textures) > 0
-        vertexColors = len(mesh.vertex_colors) > 0
-
-        mesh_extract_colors = option_colors and vertexColors
-        mesh_extract_uvs = option_uv_coords and vertexUV
-
-        if vertexUV:
-            active_uv_layer = mesh.uv_textures.active
-            if not active_uv_layer:
-                mesh_extract_uvs = False
-
-        if vertexColors:
-            active_col_layer = mesh.vertex_colors.active
-            if not active_col_layer:
-                mesh_extract_colors = False
-
-        vertex_offsets.append(vertex_offset)
-        vertex_offset += len(vertices)
-
-        vertices.extend(mesh.vertices[:])
-
-        if option_normals:
-            nnormal = extract_vertex_normals(mesh, normals, nnormal)
-
-        if mesh_extract_colors:
-            ncolor = extract_vertex_colors(mesh, colors, ncolor)
-
-        if mesh_extract_uvs:
-            nuvs = extract_uvs(mesh, uv_layers, nuvs)
-
-        if option_materials:
-            mesh_materials, nmaterial = generate_materials_string(mesh, scene, mesh_extract_colors, object.draw_type, option_copy_textures, filepath, nmaterial)
-            materials.append(mesh_materials)
-
-
-    morphTargets_string = ""
-    nmorphTarget = 0
-
-    if option_animation_morph:
-        chunks = []
-        for i, morphVertices in enumerate(morphs):
-            morphTarget = '{ "name": "%s_%06d", "vertices": [%s] }' % ("animation", i, morphVertices)
-            chunks.append(morphTarget)
-
-        morphTargets_string = ",\n\t".join(chunks)
-        nmorphTarget = len(morphs)
-
-    if align_model == 1:
-        center(vertices)
-    elif align_model == 2:
-        bottom(vertices)
-    elif align_model == 3:
-        top(vertices)
-
-    faces_string, nfaces = generate_faces(normals, uv_layers, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces)
-
-    bones_string, nbone = generate_bones(option_bones, flipyz)
-    indices_string, weights_string = generate_indices_and_weights(meshes, option_skinning)
-
-    materials_string = ",\n\n".join(materials)
-
-    model_string = TEMPLATE_MODEL_ASCII % {
-    "scale" : option_scale,
-
-    "uvs"       : generate_uvs(uv_layers, option_uv_coords),
-    "normals"   : generate_normals(normals, option_normals),
-    "colors"    : generate_vertex_colors(colors, option_colors),
-
-    "materials" : materials_string,
-
-    "vertices" : generate_vertices(vertices, option_vertices_truncate, option_vertices),
-
-    "faces"    : faces_string,
-
-    "morphTargets" : morphTargets_string,
-
-    "bones"     : bones_string,
-    "indices"   : indices_string,
-    "weights"   : weights_string,
-    "animation" : generate_animation(option_animation_skeletal, option_frame_step, flipyz)
-    }
-
-    text = TEMPLATE_FILE_ASCII % {
-    "nvertex"   : len(vertices),
-    "nface"     : nfaces,
-    "nuvs"      : ",".join("%d" % n for n in nuvs),
-    "nnormal"   : nnormal,
-    "ncolor"    : ncolor,
-    "nmaterial" : nmaterial,
-    "nmorphTarget": nmorphTarget,
-    "nbone"     : nbone,
-
-    "model"     : model_string
-    }
-
-
-    return text, model_string
-
-
-# #####################################################
-# Model exporter - export single mesh
-# #####################################################
-
-def extract_meshes(objects, scene, export_single_model, option_scale, flipyz):
-
-    meshes = []
-
-    for object in objects:
-
-        if object.type == "MESH" and object.THREE_exportGeometry:
-
-            # collapse modifiers into mesh
-
-            mesh = object.to_mesh(scene, True, 'RENDER')
-
-            if not mesh:
-                raise Exception("Error, could not get mesh data from object [%s]" % object.name)
-
-            # preserve original name
-
-            mesh.name = object.name
-
-            if export_single_model:
-
-                if flipyz:
-
-                    # that's what Blender's native export_obj.py does to flip YZ
-
-                    X_ROT = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
-                    mesh.transform(X_ROT * object.matrix_world)
-
-                else:
-                    mesh.transform(object.matrix_world)
-
-            mesh.calc_normals()
-            mesh.calc_tessface()
-            mesh.transform(mathutils.Matrix.Scale(option_scale, 4))
-            meshes.append([mesh, object])
-
-    return meshes
-
-def generate_mesh_string(objects, scene,
-                option_vertices,
-                option_vertices_truncate,
-                option_faces,
-                option_normals,
-                option_uv_coords,
-                option_materials,
-                option_colors,
-                option_bones,
-                option_skinning,
-                align_model,
-                flipyz,
-                option_scale,
-                export_single_model,
-                option_copy_textures,
-                filepath,
-                option_animation_morph,
-                option_animation_skeletal,
-                option_frame_step):
-
-    meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
-
-    morphs = []
-
-    if option_animation_morph:
-
-        original_frame = scene.frame_current # save animation state
-
-        scene_frames = range(scene.frame_start, scene.frame_end + 1, option_frame_step)
-
-        for index, frame in enumerate(scene_frames):
-            scene.frame_set(frame, 0.0)
-
-            anim_meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
-
-            frame_vertices = []
-
-            for mesh, object in anim_meshes:
-                frame_vertices.extend(mesh.vertices[:])
-
-            if index == 0:
-                if align_model == 1:
-                    offset = center(frame_vertices)
-                elif align_model == 2:
-                    offset = bottom(frame_vertices)
-                elif align_model == 3:
-                    offset = top(frame_vertices)
-                else:
-                    offset = False
-            else:
-                if offset:
-                    translate(frame_vertices, offset)
-
-            morphVertices = generate_vertices(frame_vertices, option_vertices_truncate, option_vertices)
-            morphs.append(morphVertices)
-
-            # remove temp meshes
-
-            for mesh, object in anim_meshes:
-                bpy.data.meshes.remove(mesh)
-
-        scene.frame_set(original_frame, 0.0) # restore animation state
-
-
-    text, model_string = generate_ascii_model(meshes, morphs,
-                                scene,
-                                option_vertices,
-                                option_vertices_truncate,
-                                option_faces,
-                                option_normals,
-                                option_uv_coords,
-                                option_materials,
-                                option_colors,
-                                option_bones,
-                                option_skinning,
-                                align_model,
-                                flipyz,
-                                option_scale,
-                                option_copy_textures,
-                                filepath,
-                                option_animation_morph,
-                                option_animation_skeletal,
-                                option_frame_step)
-
-    # remove temp meshes
-
-    for mesh, object in meshes:
-        bpy.data.meshes.remove(mesh)
-
-    return text, model_string
-
-def export_mesh(objects,
-                scene, filepath,
-                option_vertices,
-                option_vertices_truncate,
-                option_faces,
-                option_normals,
-                option_uv_coords,
-                option_materials,
-                option_colors,
-                option_bones,
-                option_skinning,
-                align_model,
-                flipyz,
-                option_scale,
-                export_single_model,
-                option_copy_textures,
-                option_animation_morph,
-                option_animation_skeletal,
-                option_frame_step):
-
-    """Export single mesh"""
-
-    text, model_string = generate_mesh_string(objects,
-                scene,
-                option_vertices,
-                option_vertices_truncate,
-                option_faces,
-                option_normals,
-                option_uv_coords,
-                option_materials,
-                option_colors,
-                option_bones,
-                option_skinning,
-                align_model,
-                flipyz,
-                option_scale,
-                export_single_model,
-                option_copy_textures,
-                filepath,
-                option_animation_morph,
-                option_animation_skeletal,
-                option_frame_step)
-
-    write_file(filepath, text)
-
-    print("writing", filepath, "done")
-
-
-# #####################################################
-# Scene exporter - render elements
-# #####################################################
-
-def generate_vec4(vec):
-    return TEMPLATE_VEC4 % (vec[0], vec[1], vec[2], vec[3])
-
-def generate_vec3(vec):
-    return TEMPLATE_VEC3 % (vec[0], vec[1], vec[2])
-
-def generate_vec2(vec):
-    return TEMPLATE_VEC2 % (vec[0], vec[1])
-
-def generate_hex(number):
-    return TEMPLATE_HEX % number
-
-def generate_string(s):
-    return TEMPLATE_STRING % s
-
-def generate_string_list(src_list):
-    return ", ".join(generate_string(item) for item in src_list)
-
-def generate_section(label, content):
-    return TEMPLATE_SECTION % (label, content)
-
-def get_mesh_filename(mesh):
-    object_id = mesh["data"]["name"]
-    filename = "%s.js" % sanitize(object_id)
-    return filename
-
-def generate_material_id_list(materials):
-    chunks = []
-    for material in materials:
-        chunks.append(material.name)
-
-    return chunks
-
-def generate_group_id_list(obj):
-    chunks = []
-
-    for group in bpy.data.groups:
-        if obj.name in group.objects:
-            chunks.append(group.name)
-
-    return chunks
-
-def generate_bool_property(property):
-    if property:
-        return "true"
-    return "false"
-
-# #####################################################
-# Scene exporter - objects
-# #####################################################
-
-def generate_objects(data):
-    chunks = []
-
-    for obj in data["objects"]:
-
-        if obj.type == "MESH" and obj.THREE_exportGeometry:
-            object_id = obj.name
-
-            if len(obj.modifiers) > 0:
-                geo_name = obj.name
-            else:
-                geo_name = obj.data.name
-
-            geometry_id = "geo_%s" % geo_name
-
-            material_ids = generate_material_id_list(obj.material_slots)
-            group_ids = generate_group_id_list(obj)
-
-            position, quaternion, scale = obj.matrix_world.decompose()
-            rotation = quaternion.to_euler("XYZ")
-
-            # use empty material string for multi-material objects
-            # this will trigger use of MeshFaceMaterial in SceneLoader
-
-            material_string = ""
-            if len(material_ids) == 1:
-                material_string = generate_string_list(material_ids)
-
-            group_string = ""
-            if len(group_ids) > 0:
-                group_string = generate_string_list(group_ids)
-
-            castShadow = obj.THREE_castShadow
-            receiveShadow = obj.THREE_receiveShadow
-            doubleSided = obj.THREE_doubleSided
-
-            visible = True
-
-            geometry_string = generate_string(geometry_id)
-
-            object_string = TEMPLATE_OBJECT % {
-            "object_id"   : generate_string(object_id),
-            "geometry_id" : geometry_string,
-            "group_id"    : group_string,
-            "material_id" : material_string,
-
-            "position"    : generate_vec3(position),
-            "rotation"    : generate_vec3(rotation),
-            "quaternion"  : generate_vec4(quaternion),
-            "scale"       : generate_vec3(scale),
-
-            "castShadow"  : generate_bool_property(castShadow),
-            "receiveShadow"  : generate_bool_property(receiveShadow),
-            "doubleSided"  : generate_bool_property(doubleSided),
-            "visible"      : generate_bool_property(visible)
-            }
-            chunks.append(object_string)
-
-        elif obj.type == "EMPTY" or (obj.type == "MESH" and not obj.THREE_exportGeometry):
-
-            object_id = obj.name
-            group_ids = generate_group_id_list(obj)
-
-            position, quaternion, scale = obj.matrix_world.decompose()
-            rotation = quaternion.to_euler("XYZ")
-
-            group_string = ""
-            if len(group_ids) > 0:
-                group_string = generate_string_list(group_ids)
-
-            object_string = TEMPLATE_EMPTY % {
-            "object_id"   : generate_string(object_id),
-            "group_id"    : group_string,
-
-            "position"    : generate_vec3(position),
-            "rotation"    : generate_vec3(rotation),
-            "quaternion"  : generate_vec4(quaternion),
-            "scale"       : generate_vec3(scale)
-            }
-            chunks.append(object_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - geometries
-# #####################################################
-
-def generate_geometries(data):
-    chunks = []
-
-    geo_set = set()
-
-    for obj in data["objects"]:
-        if obj.type == "MESH" and obj.THREE_exportGeometry:
-
-            if len(obj.modifiers) > 0:
-                name = obj.name
-            else:
-                name = obj.data.name
-
-            if name not in geo_set:
-
-                geometry_id = "geo_%s" % name
-
-                if data["embed_meshes"]:
-
-                    embed_id = "emb_%s" % name
-
-                    geometry_string = TEMPLATE_GEOMETRY_EMBED % {
-                    "geometry_id" : generate_string(geometry_id),
-                    "embed_id"  : generate_string(embed_id)
-                    }
-
-                else:
-
-                    model_filename = os.path.basename(generate_mesh_filename(name, data["filepath"]))
-
-                    geometry_string = TEMPLATE_GEOMETRY_LINK % {
-                    "geometry_id" : generate_string(geometry_id),
-                    "model_file"  : generate_string(model_filename)
-                    }
-
-                chunks.append(geometry_string)
-
-                geo_set.add(name)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - textures
-# #####################################################
-
-def generate_textures_scene(data):
-    chunks = []
-
-    # TODO: extract just textures actually used by some objects in the scene
-
-    for texture in bpy.data.textures:
-
-        if texture.type == 'IMAGE' and texture.image:
-
-            img = texture.image
-
-            texture_id = img.name
-            texture_file = extract_texture_filename(img)
-
-            if data["copy_textures"]:
-                save_image(img, texture_file, data["filepath"])
-
-            extras = ""
-
-            if texture.repeat_x != 1 or texture.repeat_y != 1:
-                extras += ',\n        "repeat": [%g, %g]' % (texture.repeat_x, texture.repeat_y)
-
-            if texture.extension == "REPEAT":
-                wrap_x = "repeat"
-                wrap_y = "repeat"
-
-                if texture.use_mirror_x:
-                    wrap_x = "mirror"
-                if texture.use_mirror_y:
-                    wrap_y = "mirror"
-
-                extras += ',\n        "wrap": ["%s", "%s"]' % (wrap_x, wrap_y)
-
-            texture_string = TEMPLATE_TEXTURE % {
-            "texture_id"   : generate_string(texture_id),
-            "texture_file" : generate_string(texture_file),
-            "extras"       : extras
-            }
-            chunks.append(texture_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-def extract_texture_filename(image):
-    fn = bpy.path.abspath(image.filepath)
-    fn = os.path.normpath(fn)
-    fn_strip = os.path.basename(fn)
-    return fn_strip
-
-def save_image(img, name, fpath):
-    dst_dir = os.path.dirname(fpath)
-    dst_path = os.path.join(dst_dir, name)
-
-    ensure_folder_exist(dst_dir)
-
-    if img.packed_file:
-        img.save_render(dst_path)
-
-    else:
-        src_path = bpy.path.abspath(img.filepath)
-        shutil.copy(src_path, dst_dir)
-
-# #####################################################
-# Scene exporter - materials
-# #####################################################
-
-def extract_material_data(m, option_colors):
-    world = bpy.context.scene.world
-
-    material = { 'name': m.name }
-
-    material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
-                                m.diffuse_intensity * m.diffuse_color[1],
-                                m.diffuse_intensity * m.diffuse_color[2]]
-
-    material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
-                                 m.specular_intensity * m.specular_color[1],
-                                 m.specular_intensity * m.specular_color[2]]
-
-    material['colorAmbient'] = [m.ambient * material['colorDiffuse'][0],
-                                m.ambient * material['colorDiffuse'][1],
-                                m.ambient * material['colorDiffuse'][2]]
-
-    material['transparency'] = m.alpha
-
-    # not sure about mapping values to Blinn-Phong shader
-    # Blender uses INT from [1,511] with default 0
-    # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
-
-    material["specularCoef"] = m.specular_hardness
-
-    material["vertexColors"] = m.THREE_useVertexColors and option_colors
-
-    material['mapDiffuse'] = ""
-    material['mapLight'] = ""
-    material['mapSpecular'] = ""
-    material['mapNormal'] = ""
-    material['mapBump'] = ""
-
-    material['mapNormalFactor'] = 1.0
-    material['mapBumpScale'] = 1.0
-
-    textures = guess_material_textures(m)
-
-    if textures['diffuse']:
-        material['mapDiffuse'] = textures['diffuse']['texture'].image.name
-
-    if textures['light']:
-        material['mapLight'] = textures['light']['texture'].image.name
-
-    if textures['specular']:
-        material['mapSpecular'] = textures['specular']['texture'].image.name
-
-    if textures['normal']:
-        material['mapNormal'] = textures['normal']['texture'].image.name
-        if textures['normal']['slot'].use_map_normal:
-            material['mapNormalFactor'] = textures['normal']['slot'].normal_factor
-
-    if textures['bump']:
-        material['mapBump'] = textures['bump']['texture'].image.name
-        if textures['normal']['slot'].use_map_normal:
-            material['mapBumpScale'] = textures['normal']['slot'].normal_factor
-
-    material['shading'] = m.THREE_materialType
-    material['blending'] = m.THREE_blendingType
-    material['depthWrite'] = m.THREE_depthWrite
-    material['depthTest'] = m.THREE_depthTest
-    material['transparent'] = m.use_transparency
-
-    return material
-
-def guess_material_textures(material):
-    textures = {
-        'diffuse' : None,
-        'light'   : None,
-        'normal'  : None,
-        'specular': None,
-        'bump'    : None
-    }
-
-    # just take first textures of each, for the moment three.js materials can't handle more
-    # assume diffuse comes before lightmap, normalmap has checked flag
-
-    for i in range(len(material.texture_slots)):
-        slot = material.texture_slots[i]
-        if slot:
-            texture = slot.texture
-            if slot.use and texture and texture.type == 'IMAGE':
-
-                # normal map in Blender UI: textures => image sampling => normal map
-
-                if texture.use_normal_map:
-                    textures['normal'] = { "texture": texture, "slot": slot }
-
-                # bump map in Blender UI: textures => influence => geometry => normal
-
-                elif slot.use_map_normal:
-                    textures['bump'] = { "texture": texture, "slot": slot }
-
-                elif slot.use_map_specular or slot.use_map_hardness:
-                    textures['specular'] = { "texture": texture, "slot": slot }
-
-                else:
-                    if not textures['diffuse'] and not slot.blend_type == 'MULTIPLY':
-                        textures['diffuse'] = { "texture": texture, "slot": slot }
-
-                    else:
-                        textures['light'] = { "texture": texture, "slot": slot }
-
-                if textures['diffuse'] and textures['normal'] and textures['light'] and textures['specular'] and textures['bump']:
-                    break
-
-    return textures
-
-def generate_material_string(material):
-
-    material_id = material["name"]
-
-    # default to Lambert
-
-    shading = material.get("shading", "Lambert")
-
-    # normal and bump mapped materials must use Phong
-    # to get all required parameters for normal shader
-
-    if material['mapNormal'] or material['mapBump']:
-        shading = "Phong"
-
-    type_map = {
-    "Lambert"   : "MeshLambertMaterial",
-    "Phong"     : "MeshPhongMaterial"
-    }
-
-    material_type = type_map.get(shading, "MeshBasicMaterial")
-
-    parameters = '"color": %d' % rgb2int(material["colorDiffuse"])
-    parameters += ', "opacity": %.2g' % material["transparency"]
-
-    if shading == "Phong":
-        parameters += ', "ambient": %d' % rgb2int(material["colorAmbient"])
-        parameters += ', "specular": %d' % rgb2int(material["colorSpecular"])
-        parameters += ', "shininess": %.1g' % material["specularCoef"]
-
-    colorMap = material['mapDiffuse']
-    lightMap = material['mapLight']
-    specularMap = material['mapSpecular']
-    normalMap = material['mapNormal']
-    bumpMap = material['mapBump']
-    normalMapFactor = material['mapNormalFactor']
-    bumpMapScale = material['mapBumpScale']
-
-    if colorMap:
-        parameters += ', "map": %s' % generate_string(colorMap)
-    if lightMap:
-        parameters += ', "lightMap": %s' % generate_string(lightMap)
-    if specularMap:
-        parameters += ', "specularMap": %s' % generate_string(specularMap)
-    if normalMap:
-        parameters += ', "normalMap": %s' % generate_string(normalMap)
-    if bumpMap:
-        parameters += ', "bumpMap": %s' % generate_string(bumpMap)
-
-    if normalMapFactor != 1.0:
-        parameters += ', "normalMapFactor": %g' % normalMapFactor
-
-    if bumpMapScale != 1.0:
-        parameters += ', "bumpMapScale": %g' % bumpMapScale
-
-    if material['vertexColors']:
-        parameters += ', "vertexColors": "vertex"'
-
-    if material['transparent']:
-        parameters += ', "transparent": true'
-
-    parameters += ', "blending": "%s"' % material['blending']
-
-    if not material['depthWrite']:
-        parameters += ', "depthWrite": false'
-
-    if not material['depthTest']:
-        parameters += ', "depthTest": false'
-
-
-    material_string = TEMPLATE_MATERIAL_SCENE % {
-    "material_id" : generate_string(material_id),
-    "type"        : generate_string(material_type),
-    "parameters"  : parameters
-    }
-
-    return material_string
-
-def generate_materials_scene(data):
-    chunks = []
-
-    # TODO: extract just materials actually used by some objects in the scene
-
-    for m in bpy.data.materials:
-        material = extract_material_data(m, data["use_colors"])
-        material_string = generate_material_string(material)
-        chunks.append(material_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - cameras
-# #####################################################
-
-def generate_cameras(data):
-    chunks = []
-
-    if data["use_cameras"]:
-
-        cams = bpy.data.objects
-        cams = [ob for ob in cams if (ob.type == 'CAMERA' and ob.select)]
-
-        if not cams:
-            camera = DEFAULTS["camera"]
-
-            if camera["type"] == "PerspectiveCamera":
-
-                camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
-                "camera_id" : generate_string(camera["name"]),
-                "fov"       : camera["fov"],
-                "aspect"    : camera["aspect"],
-                "near"      : camera["near"],
-                "far"       : camera["far"],
-                "position"  : generate_vec3(camera["position"]),
-                "target"    : generate_vec3(camera["target"])
-                }
-
-            elif camera["type"] == "OrthographicCamera":
-
-                camera_string = TEMPLATE_CAMERA_ORTHO % {
-                "camera_id" : generate_string(camera["name"]),
-                "left"      : camera["left"],
-                "right"     : camera["right"],
-                "top"       : camera["top"],
-                "bottom"    : camera["bottom"],
-                "near"      : camera["near"],
-                "far"       : camera["far"],
-                "position"  : generate_vec3(camera["position"]),
-                "target"    : generate_vec3(camera["target"])
-                }
-
-            chunks.append(camera_string)
-
-        else:
-
-            for cameraobj in cams:
-                camera = bpy.data.cameras[cameraobj.name]
-
-                # TODO:
-                #   Support more than perspective camera
-                #   Calculate a target/lookat
-                #   Get correct aspect ratio
-                if camera.id_data.type == "PERSP":
-
-                    camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
-                    "camera_id" : generate_string(camera.name),
-                    "fov"       : (camera.angle / 3.14) * 180.0,
-                    "aspect"    : 1.333,
-                    "near"      : camera.clip_start,
-                    "far"       : camera.clip_end,
-                    "position"  : generate_vec3([cameraobj.location[0], -cameraobj.location[1], cameraobj.location[2]]),
-                    "target"    : generate_vec3([0, 0, 0])
-                    }
-
-                chunks.append(camera_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - lights
-# #####################################################
-
-def generate_lights(data):
-    chunks = []
-
-    if data["use_lights"]:
-
-        lights = data.get("lights", [])
-        if not lights:
-            lights.append(DEFAULTS["light"])
-
-        for light in lights:
-
-            if light["type"] == "DirectionalLight":
-                light_string = TEMPLATE_LIGHT_DIRECTIONAL % {
-                "light_id"      : generate_string(light["name"]),
-                "direction"     : generate_vec3(light["direction"]),
-                "color"         : rgb2int(light["color"]),
-                "intensity"     : light["intensity"]
-                }
-
-            elif light["type"] == "PointLight":
-                light_string = TEMPLATE_LIGHT_POINT % {
-                "light_id"      : generate_string(light["name"]),
-                "position"      : generate_vec3(light["position"]),
-                "color"         : rgb2int(light["color"]),
-                "intensity"     : light["intensity"]
-                }
-
-            chunks.append(light_string)
-
-    return ",\n\n".join(chunks), len(chunks)
-
-# #####################################################
-# Scene exporter - embedded meshes
-# #####################################################
-
-def generate_embeds(data):
-
-    if data["embed_meshes"]:
-
-        chunks = []
-
-        for e in data["embeds"]:
-
-            embed = '"emb_%s": {%s}' % (e, data["embeds"][e])
-            chunks.append(embed)
-
-        return ",\n\n".join(chunks)
-
-    return ""
-
-# #####################################################
-# Scene exporter - generate ASCII scene
-# #####################################################
-
-def generate_ascii_scene(data):
-
-    objects, nobjects = generate_objects(data)
-    geometries, ngeometries = generate_geometries(data)
-    textures, ntextures = generate_textures_scene(data)
-    materials, nmaterials = generate_materials_scene(data)
-    lights, nlights = generate_lights(data)
-    cameras, ncameras = generate_cameras(data)
-
-    embeds = generate_embeds(data)
-
-    if nlights > 0:
-        if nobjects > 0:
-            objects = objects + ",\n\n" + lights
-        else:
-            objects = lights
-        nobjects += nlights
-
-    if ncameras > 0:
-        if nobjects > 0:
-            objects = objects + ",\n\n" + cameras
-        else:
-            objects = cameras
-        nobjects += ncameras
-
-    basetype = "relativeTo"
-
-    if data["base_html"]:
-        basetype += "HTML"
-    else:
-        basetype += "Scene"
-
-    sections = [
-    ["objects",    objects],
-    ["geometries", geometries],
-    ["textures",   textures],
-    ["materials",  materials],
-    ["embeds",     embeds]
-    ]
-
-    chunks = []
-    for label, content in sections:
-        if content:
-            chunks.append(generate_section(label, content))
-
-    sections_string = "\n".join(chunks)
-
-    default_camera = ""
-    if data["use_cameras"]:
-        cams = [ob for ob in bpy.data.objects if (ob.type == 'CAMERA' and ob.select)]
-        if not cams:
-            default_camera = "default_camera"
-        else:
-            default_camera = cams[0].name
-
-    parameters = {
-    "fname"     : data["source_file"],
-
-    "sections"  : sections_string,
-
-    "bgcolor"   : generate_vec3(DEFAULTS["bgcolor"]),
-    "bgalpha"   : DEFAULTS["bgalpha"],
-    "defcamera" :  generate_string(default_camera),
-
-    "nobjects"      : nobjects,
-    "ngeometries"   : ngeometries,
-    "ntextures"     : ntextures,
-    "basetype"      : generate_string(basetype),
-    "nmaterials"    : nmaterials,
-
-    "position"      : generate_vec3(DEFAULTS["position"]),
-    "rotation"      : generate_vec3(DEFAULTS["rotation"]),
-    "scale"         : generate_vec3(DEFAULTS["scale"])
-    }
-
-    text = TEMPLATE_SCENE_ASCII % parameters
-
-    return text
-
-def export_scene(scene, filepath, flipyz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds, option_url_base_html, option_copy_textures):
-
-    source_file = os.path.basename(bpy.data.filepath)
-
-    # objects are contained in scene and linked groups
-    objects = []
-
-    # get scene objects
-    sceneobjects = scene.objects
-    for obj in sceneobjects:
-      objects.append(obj)
-
-    # get linked group objcts
-    for group in bpy.data.groups:
-       for object in group.objects:
-          objects.append(object)
-
-    scene_text = ""
-    data = {
-    "scene"        : scene,
-    "objects"      : objects,
-    "embeds"       : embeds,
-    "source_file"  : source_file,
-    "filepath"     : filepath,
-    "flipyz"       : flipyz,
-    "use_colors"   : option_colors,
-    "use_lights"   : option_lights,
-    "use_cameras"  : option_cameras,
-    "embed_meshes" : option_embed_meshes,
-    "base_html"    : option_url_base_html,
-    "copy_textures": option_copy_textures
-    }
-    scene_text += generate_ascii_scene(data)
-
-    write_file(filepath, scene_text)
-
-# #####################################################
-# Main
-# #####################################################
-
-def save(operator, context, filepath = "",
-         option_flip_yz = True,
-         option_vertices = True,
-         option_vertices_truncate = False,
-         option_faces = True,
-         option_normals = True,
-         option_uv_coords = True,
-         option_materials = True,
-         option_colors = True,
-         option_bones = True,
-         option_skinning = True,
-         align_model = 0,
-         option_export_scene = False,
-         option_lights = False,
-         option_cameras = False,
-         option_scale = 1.0,
-         option_embed_meshes = True,
-         option_url_base_html = False,
-         option_copy_textures = False,
-         option_animation_morph = False,
-         option_animation_skeletal = False,
-         option_frame_step = 1,
-         option_all_meshes = True):
-
-    #print("URL TYPE", option_url_base_html)
-
-    filepath = ensure_extension(filepath, '.js')
-
-    scene = context.scene
-
-    if scene.objects.active:
-        bpy.ops.object.mode_set(mode='OBJECT')
-
-    if option_all_meshes:
-        sceneobjects = scene.objects
-    else:
-        sceneobjects = context.selected_objects
-
-    # objects are contained in scene and linked groups
-    objects = []
-
-    # get scene objects
-    for obj in sceneobjects:
-      objects.append(obj)
-
-    # get objects in linked groups
-    for group in bpy.data.groups:
-       for object in group.objects:
-          objects.append(object)
-
-    if option_export_scene:
-
-        geo_set = set()
-        embeds = {}
-
-        for object in objects:
-            if object.type == "MESH" and object.THREE_exportGeometry:
-
-                # create extra copy of geometry with applied modifiers
-                # (if they exist)
-
-                if len(object.modifiers) > 0:
-                    name = object.name
-
-                # otherwise can share geometry
-
-                else:
-                    name = object.data.name
-
-                if name not in geo_set:
-
-                    if option_embed_meshes:
-
-                        text, model_string = generate_mesh_string([object], scene,
-                                                        option_vertices,
-                                                        option_vertices_truncate,
-                                                        option_faces,
-                                                        option_normals,
-                                                        option_uv_coords,
-                                                        option_materials,
-                                                        option_colors,
-                                                        option_bones,
-                                                        option_skinning,
-                                                        False,          # align_model
-                                                        option_flip_yz,
-                                                        option_scale,
-                                                        False,          # export_single_model
-                                                        False,          # option_copy_textures
-                                                        filepath,
-                                                        option_animation_morph,
-                                                        option_animation_skeletal,
-                                                        option_frame_step)
-
-                        embeds[name] = model_string
-
-                    else:
-
-                        fname = generate_mesh_filename(name, filepath)
-                        export_mesh([object], scene,
-                                    fname,
-                                    option_vertices,
-                                    option_vertices_truncate,
-                                    option_faces,
-                                    option_normals,
-                                    option_uv_coords,
-                                    option_materials,
-                                    option_colors,
-                                    option_bones,
-                                    option_skinning,
-                                    False,          # align_model
-                                    option_flip_yz,
-                                    option_scale,
-                                    False,          # export_single_model
-                                    option_copy_textures,
-                                    option_animation_morph,
-                                    option_animation_skeletal,
-                                    option_frame_step)
-
-                    geo_set.add(name)
-
-        export_scene(scene, filepath,
-                     option_flip_yz,
-                     option_colors,
-                     option_lights,
-                     option_cameras,
-                     option_embed_meshes,
-                     embeds,
-                     option_url_base_html,
-                     option_copy_textures)
-
-    else:
-
-        export_mesh(objects, scene, filepath,
-                    option_vertices,
-                    option_vertices_truncate,
-                    option_faces,
-                    option_normals,
-                    option_uv_coords,
-                    option_materials,
-                    option_colors,
-                    option_bones,
-                    option_skinning,
-                    align_model,
-                    option_flip_yz,
-                    option_scale,
-                    True,            # export_single_model
-                    option_copy_textures,
-                    option_animation_morph,
-                    option_animation_skeletal,
-                    option_frame_step)
-
-    return {'FINISHED'}

+ 0 - 633
utils/exporters/blender/2.64/scripts/addons/io_mesh_threejs/import_threejs.py

@@ -1,633 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-"""
-Blender importer for Three.js (ASCII JSON format).
-
-"""
-
-import os
-import time
-import json
-import bpy
-import mathutils
-from mathutils.geometry import tessellate_polygon
-from bpy_extras.image_utils import load_image
-
-# #####################################################
-# Generators
-# #####################################################
-def setColor(c, t):
-    c.r = t[0]
-    c.g = t[1]
-    c.b = t[2]
-
-def create_texture(filename, modelpath):
-    name = filename
-    texture = bpy.data.textures.new(name, type='IMAGE')
-
-    image = load_image(filename, modelpath)
-    has_data = False
-
-    if image:
-        texture.image = image
-        has_data = image.has_data
-
-    return texture
-
-def create_materials(data, modelpath):
-    materials = []
-    materials_data = data.get("materials", [])
-
-    for i, m in enumerate(materials_data):
-
-        name = m.get("DbgName", "material_%d" % i)
-
-        colorAmbient = m.get("colorAmbient", None)
-        colorDiffuse = m.get("colorDiffuse", None)
-        colorSpecular = m.get("colorSpecular", None)
-        alpha = m.get("transparency", 1.0)
-        specular_hardness = m.get("specularCoef", 0)
-
-        mapDiffuse = m.get("mapDiffuse", None)
-        mapLightmap = m.get("mapLightmap", None)
-
-        vertexColorsType = m.get("vertexColors", False)
-
-        useVertexColors = False
-        if vertexColorsType:
-            useVertexColors = True
-
-        material = bpy.data.materials.new(name)
-
-        material.THREE_useVertexColors = useVertexColors
-
-        if colorDiffuse:
-            setColor(material.diffuse_color, colorDiffuse)
-            material.diffuse_intensity = 1.0
-
-        if colorSpecular:
-            setColor(material.specular_color, colorSpecular)
-            material.specular_intensity = 1.0
-
-        if alpha < 1.0:
-            material.alpha = alpha
-            material.use_transparency = True
-
-        if specular_hardness:
-            material.specular_hardness = specular_hardness
-
-        if mapDiffuse:
-            texture = create_texture(mapDiffuse, modelpath)
-            mtex = material.texture_slots.add()
-            mtex.texture = texture
-            mtex.texture_coords = 'UV'
-            mtex.use = True
-            mtex.use_map_color_diffuse = True
-
-            material.active_texture = texture
-
-        materials.append(material)
-
-    return materials
-
-def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate_normals):
-
-    faces         = face_data["faces"]
-    vertexNormals = face_data["vertexNormals"]
-    vertexColors  = face_data["vertexColors"]
-    vertexUVs     = face_data["vertexUVs"]
-    faceMaterials = face_data["materials"]
-    faceColors    = face_data["faceColors"]
-
-    edges = []
-
-    # Create a new mesh
-
-    me = bpy.data.meshes.new(name)
-    me.from_pydata(vertices, edges, faces)
-
-    # Handle normals
-
-    if not recalculate_normals:
-        me.update(calc_edges = True)
-
-    if face_data["hasVertexNormals"]:
-
-        print("setting vertex normals")
-
-        for fi in range(len(faces)):
-
-            if vertexNormals[fi]:
-
-                #print("setting face %i with %i vertices" % (fi, len(normals[fi])))
-
-                # if me.update() is called after setting vertex normals
-                # setting face.use_smooth overrides these normals
-                #  - this fixes weird shading artefacts (seems to come from sharing
-                #    of vertices between faces, didn't find a way how to set vertex normals
-                #    per face use of vertex as opposed to per vertex),
-                #  - probably this just overrides all custom vertex normals
-                #  - to preserve vertex normals from the original data
-                #    call me.update() before setting them
-
-                me.faces[fi].use_smooth = True
-
-                if not recalculate_normals:
-                    for j in range(len(vertexNormals[fi])):
-
-                        vertexNormal = vertexNormals[fi][j]
-
-                        x = vertexNormal[0]
-                        y = vertexNormal[1]
-                        z = vertexNormal[2]
-
-                        if flipYZ:
-                            tmp = y
-                            y = -z
-                            z = tmp
-
-                            # flip normals (this make them look consistent with the original before export)
-
-                            #x = -x
-                            #y = -y
-                            #z = -z
-
-                        vi = me.faces[fi].vertices[j]
-
-                        me.vertices[vi].normal.x = x
-                        me.vertices[vi].normal.y = y
-                        me.vertices[vi].normal.z = z
-
-    if recalculate_normals:
-        me.update(calc_edges = True)
-
-    # Handle colors
-
-    if face_data["hasVertexColors"]:
-
-        print("setting vertex colors")
-
-        me.vertex_colors.new("vertex_color_layer_0")
-
-        for fi in range(len(faces)):
-
-            if vertexColors[fi]:
-
-                face_colors = me.vertex_colors[0].data[fi]
-                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-
-                for vi in range(len(vertexColors[fi])):
-
-                    r = vertexColors[fi][vi][0]
-                    g = vertexColors[fi][vi][1]
-                    b = vertexColors[fi][vi][2]
-
-                    face_colors[vi].r = r
-                    face_colors[vi].g = g
-                    face_colors[vi].b = b
-
-    elif face_data["hasFaceColors"]:
-
-        print("setting vertex colors from face colors")
-
-        me.vertex_colors.new("vertex_color_layer_0")
-
-        for fi in range(len(faces)):
-
-            if faceColors[fi]:
-
-                r = faceColors[fi][0]
-                g = faceColors[fi][1]
-                b = faceColors[fi][2]
-
-                face_colors = me.vertex_colors[0].data[fi]
-                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
-
-                for vi in range(len(faces[fi])):
-
-                    face_colors[vi].r = r
-                    face_colors[vi].g = g
-                    face_colors[vi].b = b
-
-    # Handle uvs
-
-    if face_data["hasVertexUVs"]:
-
-        print("setting vertex uvs")
-
-        for li, layer in enumerate(vertexUVs):
-
-            me.uv_textures.new("uv_layer_%d" % li)
-
-            for fi in range(len(faces)):
-
-                if layer[fi]:
-
-                    uv_face = me.uv_textures[li].data[fi]
-                    face_uvs = uv_face.uv1, uv_face.uv2, uv_face.uv3, uv_face.uv4
-
-                    for vi in range(len(layer[fi])):
-
-                        u = layer[fi][vi][0]
-                        v = layer[fi][vi][1]
-
-                        face_uvs[vi].x = u
-                        face_uvs[vi].y = v
-
-                    active_texture = materials[faceMaterials[fi]].active_texture
-
-                    if active_texture:
-                        uv_face.image = active_texture.image
-
-
-    # Handle materials # 1
-
-    if face_data["hasMaterials"]:
-
-
-        print("setting materials (mesh)")
-
-        for m in materials:
-
-            me.materials.append(m)
-
-        print("setting materials (faces)")
-
-        for fi in range(len(faces)):
-
-            if faceMaterials[fi] >= 0:
-
-                me.faces[fi].material_index = faceMaterials[fi]
-
-    # Create a new object
-
-    ob = bpy.data.objects.new(name, me)
-    ob.data = me                                # link the mesh data to the object
-
-
-    scene = bpy.context.scene                   # get the current scene
-    scene.objects.link(ob)                      # link the object into the scene
-
-    ob.location = scene.cursor_location         # position object at 3d-cursor
-
-
-# #####################################################
-# Faces
-# #####################################################
-
-def extract_faces(data):
-
-    result = {
-    "faces"         : [],
-    "materials"     : [],
-    "faceUVs"       : [],
-    "vertexUVs"     : [],
-    "faceNormals"   : [],
-    "vertexNormals" : [],
-    "faceColors"    : [],
-    "vertexColors"  : [],
-
-    "hasVertexNormals"  : False,
-    "hasVertexUVs"      : False,
-    "hasVertexColors"   : False,
-    "hasFaceColors"     : False,
-    "hasMaterials"      : False
-    }
-
-    faces = data.get("faces", [])
-    normals = data.get("normals", [])
-    colors = data.get("colors", [])
-
-    offset = 0
-    zLength = len(faces)
-
-    # disregard empty arrays
-
-    nUvLayers = 0
-
-    for layer in data["uvs"]:
-
-        if len(layer) > 0:
-            nUvLayers += 1
-            result["faceUVs"].append([])
-            result["vertexUVs"].append([])
-
-
-    while ( offset < zLength ):
-
-        type = faces[ offset ]
-        offset += 1
-
-        isQuad          	= isBitSet( type, 0 )
-        hasMaterial         = isBitSet( type, 1 )
-        hasFaceUv           = isBitSet( type, 2 )
-        hasFaceVertexUv     = isBitSet( type, 3 )
-        hasFaceNormal       = isBitSet( type, 4 )
-        hasFaceVertexNormal = isBitSet( type, 5 )
-        hasFaceColor	    = isBitSet( type, 6 )
-        hasFaceVertexColor  = isBitSet( type, 7 )
-
-        #print("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor)
-
-        result["hasVertexUVs"] = result["hasVertexUVs"] or hasFaceVertexUv
-        result["hasVertexNormals"] = result["hasVertexNormals"] or hasFaceVertexNormal
-        result["hasVertexColors"] = result["hasVertexColors"] or hasFaceVertexColor
-        result["hasFaceColors"] = result["hasFaceColors"] or hasFaceColor
-        result["hasMaterials"] = result["hasMaterials"] or hasMaterial
-
-        # vertices
-
-        if isQuad:
-
-            a = faces[ offset ]
-            offset += 1
-
-            b = faces[ offset ]
-            offset += 1
-
-            c = faces[ offset ]
-            offset += 1
-
-            d = faces[ offset ]
-            offset += 1
-
-            face = [a, b, c, d]
-
-            nVertices = 4
-
-        else:
-
-            a = faces[ offset ]
-            offset += 1
-
-            b = faces[ offset ]
-            offset += 1
-
-            c = faces[ offset ]
-            offset += 1
-
-            face = [a, b, c]
-
-            nVertices = 3
-
-        result["faces"].append(face)
-
-        # material
-
-        if hasMaterial:
-
-            materialIndex = faces[ offset ]
-            offset += 1
-
-        else:
-
-            materialIndex = -1
-
-        result["materials"].append(materialIndex)
-
-        # uvs
-
-        for i in range(nUvLayers):
-
-            faceUv = None
-
-            if hasFaceUv:
-
-                uvLayer = data["uvs"][ i ]
-
-                uvIndex = faces[ offset ]
-                offset += 1
-
-                u = uvLayer[ uvIndex * 2 ]
-                v = uvLayer[ uvIndex * 2 + 1 ]
-
-                faceUv = [u, v]
-
-            result["faceUVs"][i].append(faceUv)
-
-
-            if hasFaceVertexUv:
-
-                uvLayer = data["uvs"][ i ]
-
-                vertexUvs = []
-
-                for j in range(nVertices):
-
-                    uvIndex = faces[ offset ]
-                    offset += 1
-
-                    u = uvLayer[ uvIndex * 2 ]
-                    v = uvLayer[ uvIndex * 2 + 1 ]
-
-                    vertexUvs.append([u, v])
-
-            result["vertexUVs"][i].append(vertexUvs)
-
-
-        if hasFaceNormal:
-
-            normalIndex = faces[ offset ] * 3
-            offset += 1
-
-            x = normals[ normalIndex ]
-            y = normals[ normalIndex + 1 ]
-            z = normals[ normalIndex + 2 ]
-
-            faceNormal = [x, y, z]
-
-        else:
-
-            faceNormal = None
-
-        result["faceNormals"].append(faceNormal)
-
-
-        if hasFaceVertexNormal:
-
-            vertexNormals = []
-
-            for j in range(nVertices):
-
-                normalIndex = faces[ offset ] * 3
-                offset += 1
-
-                x = normals[ normalIndex ]
-                y = normals[ normalIndex + 1 ]
-                z = normals[ normalIndex + 2 ]
-
-                vertexNormals.append( [x, y, z] )
-
-
-        else:
-
-            vertexNormals = None
-
-        result["vertexNormals"].append(vertexNormals)
-
-
-        if hasFaceColor:
-
-            colorIndex = faces[ offset ]
-            offset += 1
-
-            faceColor = hexToTuple( colors[ colorIndex ] )
-
-        else:
-
-            faceColor = None
-
-        result["faceColors"].append(faceColor)
-
-
-        if hasFaceVertexColor:
-
-            vertexColors = []
-
-            for j in range(nVertices):
-
-                colorIndex = faces[ offset ]
-                offset += 1
-
-                color = hexToTuple( colors[ colorIndex ] )
-                vertexColors.append( color )
-
-        else:
-
-            vertexColors = None
-
-        result["vertexColors"].append(vertexColors)
-
-
-    return result
-
-# #####################################################
-# Utils
-# #####################################################
-
-def hexToTuple( hexColor ):
-    r = (( hexColor >> 16 ) & 0xff) / 255.0
-    g = (( hexColor >> 8 ) & 0xff) / 255.0
-    b = ( hexColor & 0xff) / 255.0
-    return (r, g, b)
-
-def isBitSet(value, position):
-    return value & ( 1 << position )
-
-def splitArray(data, chunkSize):
-    result = []
-    chunk = []
-    for i in range(len(data)):
-        if i > 0 and i % chunkSize == 0:
-            result.append(chunk)
-            chunk = []
-        chunk.append(data[i])
-    result.append(chunk)
-    return result
-
-
-def extract_json_string(text):
-    marker_begin = "var model ="
-    marker_end = "postMessage"
-
-    start = text.find(marker_begin) + len(marker_begin)
-    end = text.find(marker_end)
-    end = text.rfind("}", start, end)
-    return text[start:end+1].strip()
-
-def get_name(filepath):
-    return os.path.splitext(os.path.basename(filepath))[0]
-
-def get_path(filepath):
-    return os.path.dirname(filepath)
-
-# #####################################################
-# Parser
-# #####################################################
-
-def load(operator, context, filepath, option_flip_yz = True, recalculate_normals = True, option_worker = False):
-
-    print('\nimporting %r' % filepath)
-
-    time_main = time.time()
-
-    print("\tparsing JSON file...")
-
-    time_sub = time.time()
-
-    file = open(filepath, 'rU')
-    rawcontent = file.read()
-    file.close()
-
-    if option_worker:
-        json_string = extract_json_string(rawcontent)
-    else:
-        json_string = rawcontent
-    data = json.loads( json_string )
-
-    time_new = time.time()
-
-    print('parsing %.4f sec' % (time_new - time_sub))
-
-    time_sub = time_new
-
-    # flip YZ
-
-    vertices = splitArray(data["vertices"], 3)
-
-    if option_flip_yz:
-        vertices[:] = [(v[0], -v[2], v[1]) for v in vertices]
-
-    # extract faces
-
-    face_data = extract_faces(data)
-
-    # deselect all
-
-    bpy.ops.object.select_all(action='DESELECT')
-
-    nfaces = len(face_data["faces"])
-    nvertices = len(vertices)
-    nnormals = len(data.get("normals", [])) / 3
-    ncolors = len(data.get("colors", [])) / 3
-    nuvs = len(data.get("uvs", [])) / 2
-    nmaterials = len(data.get("materials", []))
-
-    print('\tbuilding geometry...\n\tfaces:%i, vertices:%i, vertex normals: %i, vertex uvs: %i, vertex colors: %i, materials: %i ...' % (
-        nfaces, nvertices, nnormals, nuvs, ncolors, nmaterials ))
-
-    # Create materials
-
-    materials = create_materials(data, get_path(filepath))
-
-    # Create new obj
-
-    create_mesh_object(get_name(filepath), vertices, materials, face_data, option_flip_yz, recalculate_normals)
-
-    scene = bpy.context.scene
-    scene.update()
-
-    time_new = time.time()
-
-    print('finished importing: %r in %.4f sec.' % (filepath, (time_new - time_main)))
-    return {'FINISHED'}
-
-
-if __name__ == "__main__":
-    register()

+ 3 - 6
utils/exporters/blender/README.md

@@ -2,8 +2,6 @@
 
 Imports and exports Three.js' ASCII JSON format.
 
-Assumes Blender version 2.60.
-
 ## Installation
 
 Copy the io_mesh_threejs folder to the scripts/addons folder. If it doesn't exist, create it. The full path is OS-dependent (see below).
@@ -17,21 +15,20 @@ Goto Usage.
 
 Should look like this:
 
-    C:\Users\USERNAME\AppData\Roaming\Blender Foundation\Blender\2.60\scripts\addons
+    C:\Users\USERNAME\AppData\Roaming\Blender Foundation\Blender\2.6X\scripts\addons
 
 ### OSX
 
 Depends on where blender.app is. Assuming you copied it to your Applications folder:
 
-    /Applications/Blender/blender.app/Contents/MacOS/2.60/scripts/addons
+    /Applications/Blender/blender.app/Contents/MacOS/2.6X/scripts/addons
 
 ### Linux
 
 By default, this should look like:
 
-    /home/USERNAME/.blender/2.60/scripts/addons
+    /home/USERNAME/.blender/2.6X/scripts/addons
 
 ## Usage
 
 Use the regular Import and Export menu within Blender, select `Three.js (js)`.
-