From 77f99e2553ead0fa7f31f8f5b28183e525427308 Mon Sep 17 00:00:00 2001
From: Julien Duroure <julien.duroure@gmail.com>
Date: Tue, 12 May 2020 18:35:23 +0200
Subject: [PATCH] glTF: fix bad ending line

---
 io_scene_gltf2/__init__.py | 2012 ++++++++++++++++++------------------
 1 file changed, 1006 insertions(+), 1006 deletions(-)

diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index 09f5428b7..9f29af9e8 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -1,1006 +1,1006 @@
-# Copyright 2018-2019 The glTF-Blender-IO authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-bl_info = {
-    'name': 'glTF 2.0 format',
-    'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin SchmithĂĽsen, Jim Eckerlein, and many external contributors',
-    "version": (1, 3, 13),
-    'blender': (2, 90, 0),
-    'location': 'File > Import-Export',
-    'description': 'Import-Export as glTF 2.0',
-    'warning': '',
-    'doc_url': "{BLENDER_MANUAL_URL}/addons/import_export/scene_gltf2.html",
-    'tracker_url': "https://github.com/KhronosGroup/glTF-Blender-IO/issues/",
-    'support': 'OFFICIAL',
-    'category': 'Import-Export',
-}
-
-def get_version_string():
-    return str(bl_info['version'][0]) + '.' + str(bl_info['version'][1]) + '.' + str(bl_info['version'][2])
-
-#
-# Script reloading (if the user calls 'Reload Scripts' from Blender)
-#
-
-def reload_package(module_dict_main):
-    import importlib
-    from pathlib import Path
-
-    def reload_package_recursive(current_dir, module_dict):
-        for path in current_dir.iterdir():
-            if "__init__" in str(path) or path.stem not in module_dict:
-                continue
-
-            if path.is_file() and path.suffix == ".py":
-                importlib.reload(module_dict[path.stem])
-            elif path.is_dir():
-                reload_package_recursive(path, module_dict[path.stem].__dict__)
-
-    reload_package_recursive(Path(__file__).parent, module_dict_main)
-
-
-if "bpy" in locals():
-    reload_package(locals())
-
-import bpy
-from bpy.props import (StringProperty,
-                       BoolProperty,
-                       EnumProperty,
-                       IntProperty,
-                       CollectionProperty)
-from bpy.types import Operator
-from bpy_extras.io_utils import ImportHelper, ExportHelper
-
-
-#
-#  Functions / Classes.
-#
-
-extension_panel_unregister_functors = []
-
-class ExportGLTF2_Base:
-    # TODO: refactor to avoid boilerplate
-
-    def __init__(self):
-        from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension
-        self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists()
-
-    bl_options = {'PRESET'}
-
-    export_format: EnumProperty(
-        name='Format',
-        items=(('GLB', 'glTF Binary (.glb)',
-                'Exports a single file, with all data packed in binary form. '
-                'Most efficient and portable, but more difficult to edit later'),
-               ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
-                'Exports a single file, with all data packed in JSON. '
-                'Less efficient than binary, but easier to edit later'),
-               ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
-                'Exports multiple files, with separate JSON, binary and texture data. '
-                'Easiest to edit later')),
-        description=(
-            'Output format and embedding options. Binary is most efficient, '
-            'but JSON (embedded or separate) may be easier to edit later'
-        ),
-        default='GLB'
-    )
-
-    ui_tab: EnumProperty(
-        items=(('GENERAL', "General", "General settings"),
-               ('MESHES', "Meshes", "Mesh settings"),
-               ('OBJECTS', "Objects", "Object settings"),
-               ('ANIMATION', "Animation", "Animation settings")),
-        name="ui_tab",
-        description="Export setting categories",
-    )
-
-    export_copyright: StringProperty(
-        name='Copyright',
-        description='Legal rights and conditions for the model',
-        default=''
-    )
-
-    export_image_format: EnumProperty(
-        name='Images',
-        items=(('AUTO', 'Automatic',
-                'Save PNGs as PNGs and JPEGs as JPEGs.\n'
-                'If neither one, use PNG'),
-                ('JPEG', 'JPEG Format (.jpg)',
-                'Save images as JPEGs. (Images that need alpha are saved as PNGs though.)\n'
-                'Be aware of a possible loss in quality'),
-               ),
-        description=(
-            'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
-            'applications due to the smaller file size'
-        ),
-        default='AUTO'
-    )
-
-    export_texture_dir: StringProperty(
-        name='Textures',
-        description='Folder to place texture files in. Relative to the .gltf file',
-        default='',
-    )
-
-    export_texcoords: BoolProperty(
-        name='UVs',
-        description='Export UVs (texture coordinates) with meshes',
-        default=True
-    )
-
-    export_normals: BoolProperty(
-        name='Normals',
-        description='Export vertex normals with meshes',
-        default=True
-    )
-
-    export_draco_mesh_compression_enable: BoolProperty(
-        name='Draco mesh compression',
-        description='Compress mesh using Draco',
-        default=False
-    )
-
-    export_draco_mesh_compression_level: IntProperty(
-        name='Compression level',
-        description='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
-        default=6,
-        min=0,
-        max=6
-    )
-
-    export_draco_position_quantization: IntProperty(
-        name='Position quantization bits',
-        description='Quantization bits for position values (0 = no quantization)',
-        default=14,
-        min=0,
-        max=30
-    )
-
-    export_draco_normal_quantization: IntProperty(
-        name='Normal quantization bits',
-        description='Quantization bits for normal values (0 = no quantization)',
-        default=10,
-        min=0,
-        max=30
-    )
-
-    export_draco_texcoord_quantization: IntProperty(
-        name='Texcoord quantization bits',
-        description='Quantization bits for texture coordinate values (0 = no quantization)',
-        default=12,
-        min=0,
-        max=30
-    )
-
-    export_draco_generic_quantization: IntProperty(
-        name='Generic quantization bits',
-        description='Quantization bits for generic coordinate values like weights or joints (0 = no quantization)',
-        default=12,
-        min=0,
-        max=30
-    )
-
-    export_tangents: BoolProperty(
-        name='Tangents',
-        description='Export vertex tangents with meshes',
-        default=False
-    )
-
-    export_materials: BoolProperty(
-        name='Materials',
-        description='Export materials',
-        default=True
-    )
-
-    export_colors: BoolProperty(
-        name='Vertex Colors',
-        description='Export vertex colors with meshes',
-        default=True
-    )
-
-    export_cameras: BoolProperty(
-        name='Cameras',
-        description='Export cameras',
-        default=False
-    )
-
-    # keep it for compatibility (for now)
-    export_selected: BoolProperty(
-        name='Selected Objects',
-        description='Export selected objects only',
-        default=False
-    )
-
-    use_selection: BoolProperty(
-        name='Selected Objects',
-        description='Export selected objects only',
-        default=False
-    )
-
-    export_extras: BoolProperty(
-        name='Custom Properties',
-        description='Export custom properties as glTF extras',
-        default=False
-    )
-
-    export_yup: BoolProperty(
-        name='+Y Up',
-        description='Export using glTF convention, +Y up',
-        default=True
-    )
-
-    export_apply: BoolProperty(
-        name='Apply Modifiers',
-        description='Apply modifiers (excluding Armatures) to mesh objects -'
-                    'WARNING: prevents exporting shape keys',
-        default=False
-    )
-
-    export_animations: BoolProperty(
-        name='Animations',
-        description='Exports active actions and NLA tracks as glTF animations',
-        default=True
-    )
-
-    export_frame_range: BoolProperty(
-        name='Limit to Playback Range',
-        description='Clips animations to selected playback range',
-        default=True
-    )
-
-    export_frame_step: IntProperty(
-        name='Sampling Rate',
-        description='How often to evaluate animated values (in frames)',
-        default=1,
-        min=1,
-        max=120
-    )
-
-    export_force_sampling: BoolProperty(
-        name='Always Sample Animations',
-        description='Apply sampling to all animations',
-        default=True
-    )
-
-    export_nla_strips: BoolProperty(
-        name='Group by NLA Track',
-        description=(
-            "When on, multiple actions become part of the same glTF animation if\n"
-            "they're pushed onto NLA tracks with the same name.\n"
-            "When off, all the currently assigned actions become one glTF animation"
-        ),
-        default=True
-    )
-
-    export_def_bones: BoolProperty(
-        name='Export Deformation Bones Only',
-        description='Export Deformation bones only (and needed bones for hierarchy)',
-        default=False
-    )
-
-    export_current_frame: BoolProperty(
-        name='Use Current Frame',
-        description='Export the scene in the current animation frame',
-        default=False
-    )
-
-    export_skins: BoolProperty(
-        name='Skinning',
-        description='Export skinning (armature) data',
-        default=True
-    )
-
-    export_all_influences: BoolProperty(
-        name='Include All Bone Influences',
-        description='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
-        default=False
-    )
-
-    export_morph: BoolProperty(
-        name='Shape Keys',
-        description='Export shape keys (morph targets)',
-        default=True
-    )
-
-    export_morph_normal: BoolProperty(
-        name='Shape Key Normals',
-        description='Export vertex normals with shape keys (morph targets)',
-        default=True
-    )
-
-    export_morph_tangent: BoolProperty(
-        name='Shape Key Tangents',
-        description='Export vertex tangents with shape keys (morph targets)',
-        default=False
-    )
-
-    export_lights: BoolProperty(
-        name='Punctual Lights',
-        description='Export directional, point, and spot lights. '
-                    'Uses "KHR_lights_punctual" glTF extension',
-        default=False
-    )
-
-    export_displacement: BoolProperty(
-        name='Displacement Textures (EXPERIMENTAL)',
-        description='EXPERIMENTAL: Export displacement textures. '
-                    'Uses incomplete "KHR_materials_displacement" glTF extension',
-        default=False
-    )
-
-    will_save_settings: BoolProperty(
-        name='Remember Export Settings',
-        description='Store glTF export settings in the Blender project',
-        default=False)
-
-    # Custom scene property for saving settings
-    scene_key = "glTF2ExportSettings"
-
-    #
-
-    def invoke(self, context, event):
-        settings = context.scene.get(self.scene_key)
-        self.will_save_settings = False
-        self.has_active_extenions = False
-        if settings:
-            try:
-                for (k, v) in settings.items():
-                    if k == "export_selected": # Back compatibility for export_selected --> use_selection
-                        setattr(self, "use_selection", v)
-                        del settings[k]
-                        settings["use_selection"] = v
-                        print("export_selected is now renamed use_selection, and will be deleted in a few release")
-                    else:
-                        setattr(self, k, v)
-                self.will_save_settings = True
-
-            except (AttributeError, TypeError):
-                self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
-                del context.scene[self.scene_key]
-
-        import sys
-        preferences = bpy.context.preferences
-        for addon_name in preferences.addons.keys():
-            try:
-                if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ExportUserExtensions'):
-                    extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
-                    self.has_active_extenions = True
-            except Exception:
-                pass
-
-        return ExportHelper.invoke(self, context, event)
-
-    def save_settings(self, context):
-        # find all export_ props
-        all_props = self.properties
-        export_props = {x: getattr(self, x) for x in dir(all_props)
-                        if x.startswith("export_") and all_props.get(x) is not None}
-
-        context.scene[self.scene_key] = export_props
-
-    def execute(self, context):
-        import os
-        import datetime
-        from .blender.exp import gltf2_blender_export
-
-        if self.will_save_settings:
-            self.save_settings(context)
-
-        if self.export_format == 'GLB':
-            self.filename_ext = '.glb'
-        else:
-            self.filename_ext = '.gltf'
-
-        # All custom export settings are stored in this container.
-        export_settings = {}
-
-        export_settings['timestamp'] = datetime.datetime.now()
-
-        export_settings['gltf_filepath'] = bpy.path.ensure_ext(self.filepath, self.filename_ext)
-        export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
-        export_settings['gltf_texturedirectory'] = os.path.join(
-            export_settings['gltf_filedirectory'],
-            self.export_texture_dir,
-        )
-
-        export_settings['gltf_format'] = self.export_format
-        export_settings['gltf_image_format'] = self.export_image_format
-        export_settings['gltf_copyright'] = self.export_copyright
-        export_settings['gltf_texcoords'] = self.export_texcoords
-        export_settings['gltf_normals'] = self.export_normals
-        export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
-
-        if self.is_draco_available:
-            export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
-            export_settings['gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level
-            export_settings['gltf_draco_position_quantization'] = self.export_draco_position_quantization
-            export_settings['gltf_draco_normal_quantization'] = self.export_draco_normal_quantization
-            export_settings['gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization
-            export_settings['gltf_draco_generic_quantization'] = self.export_draco_generic_quantization
-        else:
-            export_settings['gltf_draco_mesh_compression'] = False
-
-        export_settings['gltf_materials'] = self.export_materials
-        export_settings['gltf_colors'] = self.export_colors
-        export_settings['gltf_cameras'] = self.export_cameras
-
-        # compatibility after renaming export_selected to use_selection
-        if self.export_selected is True:
-            self.report({"WARNING"}, "export_selected is now renamed use_selection, and will be deleted in a few release")
-            export_settings['gltf_selected'] = self.export_selected
-        else:
-            export_settings['gltf_selected'] = self.use_selection
-
-        # export_settings['gltf_selected'] = self.use_selection This can be uncomment when removing compatibility of export_selected
-        export_settings['gltf_layers'] = True  # self.export_layers
-        export_settings['gltf_extras'] = self.export_extras
-        export_settings['gltf_yup'] = self.export_yup
-        export_settings['gltf_apply'] = self.export_apply
-        export_settings['gltf_current_frame'] = self.export_current_frame
-        export_settings['gltf_animations'] = self.export_animations
-        if self.export_animations:
-            export_settings['gltf_frame_range'] = self.export_frame_range
-            export_settings['gltf_force_sampling'] = self.export_force_sampling
-            if self.export_force_sampling:
-                export_settings['gltf_def_bones'] = self.export_def_bones
-            else:
-                export_settings['gltf_def_bones'] = False
-            export_settings['gltf_nla_strips'] = self.export_nla_strips
-        else:
-            export_settings['gltf_frame_range'] = False
-            export_settings['gltf_move_keyframes'] = False
-            export_settings['gltf_force_sampling'] = False
-            export_settings['gltf_def_bones'] = False
-        export_settings['gltf_skins'] = self.export_skins
-        if self.export_skins:
-            export_settings['gltf_all_vertex_influences'] = self.export_all_influences
-        else:
-            export_settings['gltf_all_vertex_influences'] = False
-        export_settings['gltf_frame_step'] = self.export_frame_step
-        export_settings['gltf_morph'] = self.export_morph
-        if self.export_morph:
-            export_settings['gltf_morph_normal'] = self.export_morph_normal
-        else:
-            export_settings['gltf_morph_normal'] = False
-        if self.export_morph and self.export_morph_normal:
-            export_settings['gltf_morph_tangent'] = self.export_morph_tangent
-        else:
-            export_settings['gltf_morph_tangent'] = False
-
-        export_settings['gltf_lights'] = self.export_lights
-        export_settings['gltf_displacement'] = self.export_displacement
-
-        export_settings['gltf_binary'] = bytearray()
-        export_settings['gltf_binaryfilename'] = os.path.splitext(os.path.basename(
-            bpy.path.ensure_ext(self.filepath,self.filename_ext)))[0] + '.bin'
-
-        user_extensions = []
-
-        import sys
-        preferences = bpy.context.preferences
-        for addon_name in preferences.addons.keys():
-            try:
-                module = sys.modules[addon_name]
-            except Exception:
-                continue
-            if hasattr(module, 'glTF2ExportUserExtension'):
-                extension_ctor = module.glTF2ExportUserExtension
-                user_extensions.append(extension_ctor())
-            if hasattr(module, 'glTF2ExportUserExtensions'):
-                extension_ctors = module.glTF2ExportUserExtensions
-                for extension_ctor in extension_ctors:
-                    user_extensions.append(extension_ctor())
-        export_settings['gltf_user_extensions'] = user_extensions
-
-        return gltf2_blender_export.save(context, export_settings)
-
-    def draw(self, context):
-        pass # Is needed to get panels available
-
-
-class GLTF_PT_export_main(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = ""
-    bl_parent_id = "FILE_PT_operator"
-    bl_options = {'HIDE_HEADER'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.prop(operator, 'export_format')
-        if operator.export_format == 'GLTF_SEPARATE':
-            layout.prop(operator, 'export_texture_dir', icon='FILE_FOLDER')
-        layout.prop(operator, 'export_copyright')
-        layout.prop(operator, 'will_save_settings')
-
-
-class GLTF_PT_export_include(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Include"
-    bl_parent_id = "FILE_PT_operator"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        col = layout.column(heading = "Limit to", align = True)
-        col.prop(operator, 'use_selection')
-
-        col = layout.column(heading = "Data", align = True)
-        col.prop(operator, 'export_extras')
-        col.prop(operator, 'export_cameras')
-        col.prop(operator, 'export_lights')
-
-
-class GLTF_PT_export_transform(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Transform"
-    bl_parent_id = "FILE_PT_operator"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.prop(operator, 'export_yup')
-
-
-class GLTF_PT_export_geometry(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Geometry"
-    bl_parent_id = "FILE_PT_operator"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.prop(operator, 'export_apply')
-        layout.prop(operator, 'export_texcoords')
-        layout.prop(operator, 'export_normals')
-        col = layout.column()
-        col.active = operator.export_normals
-        col.prop(operator, 'export_tangents')
-        layout.prop(operator, 'export_colors')
-        layout.prop(operator, 'export_materials')
-        col = layout.column()
-        col.active = operator.export_materials
-        col.prop(operator, 'export_image_format')
-
-
-class GLTF_PT_export_geometry_compression(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Compression"
-    bl_parent_id = "GLTF_PT_export_geometry"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def __init__(self):
-        from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension
-        self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists(quiet=True)
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-        if operator.is_draco_available:
-            return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw_header(self, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-        self.layout.prop(operator, "export_draco_mesh_compression_enable", text="")
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.active = operator.export_draco_mesh_compression_enable
-        layout.prop(operator, 'export_draco_mesh_compression_level')
-
-        col = layout.column(align=True)
-        col.prop(operator, 'export_draco_position_quantization', text="Quantize Position")
-        col.prop(operator, 'export_draco_normal_quantization', text="Normal")
-        col.prop(operator, 'export_draco_texcoord_quantization', text="Tex Coords")
-        col.prop(operator, 'export_draco_generic_quantization', text="Generic")
-
-
-class GLTF_PT_export_animation(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Animation"
-    bl_parent_id = "FILE_PT_operator"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.prop(operator, 'export_current_frame')
-
-
-class GLTF_PT_export_animation_export(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Animation"
-    bl_parent_id = "GLTF_PT_export_animation"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw_header(self, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-        self.layout.prop(operator, "export_animations", text="")
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.active = operator.export_animations
-
-        layout.prop(operator, 'export_frame_range')
-        layout.prop(operator, 'export_frame_step')
-        layout.prop(operator, 'export_force_sampling')
-        layout.prop(operator, 'export_nla_strips')
-
-        row = layout.row()
-        row.active = operator.export_force_sampling
-        row.prop(operator, 'export_def_bones')
-
-
-class GLTF_PT_export_animation_shapekeys(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Shape Keys"
-    bl_parent_id = "GLTF_PT_export_animation"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw_header(self, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-        self.layout.prop(operator, "export_morph", text="")
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.active = operator.export_morph
-
-        layout.prop(operator, 'export_morph_normal')
-        col = layout.column()
-        col.active = operator.export_morph_normal
-        col.prop(operator, 'export_morph_tangent')
-
-
-class GLTF_PT_export_animation_skinning(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Skinning"
-    bl_parent_id = "GLTF_PT_export_animation"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
-
-    def draw_header(self, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-        self.layout.prop(operator, "export_skins", text="")
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        layout.active = operator.export_skins
-        layout.prop(operator, 'export_all_influences')
-
-class GLTF_PT_export_user_extensions(bpy.types.Panel):
-    bl_space_type = 'FILE_BROWSER'
-    bl_region_type = 'TOOL_PROPS'
-    bl_label = "Extensions"
-    bl_parent_id = "FILE_PT_operator"
-    bl_options = {'DEFAULT_CLOSED'}
-
-    @classmethod
-    def poll(cls, context):
-        sfile = context.space_data
-        operator = sfile.active_operator
-
-        return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_extenions
-
-    def draw(self, context):
-        layout = self.layout
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-
-class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
-    """Export scene as glTF 2.0 file"""
-    bl_idname = 'export_scene.gltf'
-    bl_label = 'Export glTF 2.0'
-
-    filename_ext = ''
-
-    filter_glob: StringProperty(default='*.glb;*.gltf', options={'HIDDEN'})
-
-
-def menu_func_export(self, context):
-    self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
-
-
-class ImportGLTF2(Operator, ImportHelper):
-    """Load a glTF 2.0 file"""
-    bl_idname = 'import_scene.gltf'
-    bl_label = 'Import glTF 2.0'
-
-    filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
-
-    files: CollectionProperty(
-        name="File Path",
-        type=bpy.types.OperatorFileListElement,
-    )
-
-    loglevel: IntProperty(
-        name='Log Level',
-        description="Log Level")
-
-    import_pack_images: BoolProperty(
-        name='Pack Images',
-        description='Pack all images into .blend file',
-        default=True
-    )
-
-    import_shading: EnumProperty(
-        name="Shading",
-        items=(("NORMALS", "Use Normal Data", ""),
-               ("FLAT", "Flat Shading", ""),
-               ("SMOOTH", "Smooth Shading", "")),
-        description="How normals are computed during import",
-        default="NORMALS")
-
-    bone_heuristic: EnumProperty(
-        name="Bone Dir",
-        items=(
-            ("BLENDER", "Blender (best for re-importing)",
-                "Good for re-importing glTFs exported from Blender.\n"
-                "Bone tips are placed on their local +Y axis (in glTF space)"),
-            ("TEMPERANCE", "Temperance (average)",
-                "Decent all-around strategy.\n"
-                "A bone with one child has its tip placed on the local axis\n"
-                "closest to its child"),
-            ("FORTUNE", "Fortune (may look better, less accurate)",
-                "Might look better than Temperance, but also might have errors.\n"
-                "A bone with one child has its tip placed at its child's root.\n"
-                "Non-uniform scalings may get messed up though, so beware"),
-        ),
-        description="Heuristic for placing bones. Tries to make bones pretty",
-        default="TEMPERANCE",
-    )
-
-    guess_original_bind_pose: BoolProperty(
-        name='Guess Original Bind Pose',
-        description=(
-            'Try to guess the original bind pose for skinned meshes from '
-            'the inverse bind matrices.\n'
-            'When off, use default/rest pose as bind pose'
-        ),
-        default=True,
-    )
-
-    def draw(self, context):
-        layout = self.layout
-
-        layout.use_property_split = True
-        layout.use_property_decorate = False  # No animation.
-
-        layout.prop(self, 'import_pack_images')
-        layout.prop(self, 'import_shading')
-        layout.prop(self, 'guess_original_bind_pose')
-        layout.prop(self, 'bone_heuristic')
-
-    def execute(self, context):
-        return self.import_gltf2(context)
-
-    def import_gltf2(self, context):
-        import os
-
-        self.set_debug_log()
-        import_settings = self.as_keywords()
-
-        if self.files:
-            # Multiple file import
-            ret = {'CANCELLED'}
-            dirname = os.path.dirname(self.filepath)
-            for file in self.files:
-                path = os.path.join(dirname, file.name)
-                if self.unit_import(path, import_settings) == {'FINISHED'}:
-                    ret = {'FINISHED'}
-            return ret
-        else:
-            # Single file import
-            return self.unit_import(self.filepath, import_settings)
-
-    def unit_import(self, filename, import_settings):
-        import time
-        from .io.imp.gltf2_io_gltf import glTFImporter
-        from .blender.imp.gltf2_blender_gltf import BlenderGlTF
-
-        self.gltf_importer = glTFImporter(filename, import_settings)
-        success, txt = self.gltf_importer.read()
-        if not success:
-            self.report({'ERROR'}, txt)
-            return {'CANCELLED'}
-        success, txt = self.gltf_importer.checks()
-        if not success:
-            self.report({'ERROR'}, txt)
-            return {'CANCELLED'}
-        print("Data are loaded, start creating Blender stuff")
-        start_time = time.time()
-        BlenderGlTF.create(self.gltf_importer)
-        elapsed_s = "{:.2f}s".format(time.time() - start_time)
-        print("glTF import finished in " + elapsed_s)
-        self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler)
-
-        return {'FINISHED'}
-
-    def set_debug_log(self):
-        import logging
-        if bpy.app.debug_value == 0:
-            self.loglevel = logging.CRITICAL
-        elif bpy.app.debug_value == 1:
-            self.loglevel = logging.ERROR
-        elif bpy.app.debug_value == 2:
-            self.loglevel = logging.WARNING
-        elif bpy.app.debug_value == 3:
-            self.loglevel = logging.INFO
-        else:
-            self.loglevel = logging.NOTSET
-
-
-def menu_func_import(self, context):
-    self.layout.operator(ImportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
-
-
-classes = (
-    ExportGLTF2,
-    GLTF_PT_export_main,
-    GLTF_PT_export_include,
-    GLTF_PT_export_transform,
-    GLTF_PT_export_geometry,
-    GLTF_PT_export_geometry_compression,
-    GLTF_PT_export_animation,
-    GLTF_PT_export_animation_export,
-    GLTF_PT_export_animation_shapekeys,
-    GLTF_PT_export_animation_skinning,
-    GLTF_PT_export_user_extensions,
-    ImportGLTF2
-)
-
-
-def register():
-    for c in classes:
-        bpy.utils.register_class(c)
-    # bpy.utils.register_module(__name__)
-
-    # add to the export / import menu
-    bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
-    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
-
-
-def unregister():
-    for c in classes:
-        bpy.utils.unregister_class(c)
-    for f in extension_panel_unregister_functors:
-        f()
-    extension_panel_unregister_functors.clear()
-
-    # bpy.utils.unregister_module(__name__)
-
-    # remove from the export / import menu
-    bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
-    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
+# Copyright 2018-2019 The glTF-Blender-IO authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+bl_info = {
+    'name': 'glTF 2.0 format',
+    'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin SchmithĂĽsen, Jim Eckerlein, and many external contributors',
+    "version": (1, 3, 13),
+    'blender': (2, 90, 0),
+    'location': 'File > Import-Export',
+    'description': 'Import-Export as glTF 2.0',
+    'warning': '',
+    'doc_url': "{BLENDER_MANUAL_URL}/addons/import_export/scene_gltf2.html",
+    'tracker_url': "https://github.com/KhronosGroup/glTF-Blender-IO/issues/",
+    'support': 'OFFICIAL',
+    'category': 'Import-Export',
+}
+
+def get_version_string():
+    return str(bl_info['version'][0]) + '.' + str(bl_info['version'][1]) + '.' + str(bl_info['version'][2])
+
+#
+# Script reloading (if the user calls 'Reload Scripts' from Blender)
+#
+
+def reload_package(module_dict_main):
+    import importlib
+    from pathlib import Path
+
+    def reload_package_recursive(current_dir, module_dict):
+        for path in current_dir.iterdir():
+            if "__init__" in str(path) or path.stem not in module_dict:
+                continue
+
+            if path.is_file() and path.suffix == ".py":
+                importlib.reload(module_dict[path.stem])
+            elif path.is_dir():
+                reload_package_recursive(path, module_dict[path.stem].__dict__)
+
+    reload_package_recursive(Path(__file__).parent, module_dict_main)
+
+
+if "bpy" in locals():
+    reload_package(locals())
+
+import bpy
+from bpy.props import (StringProperty,
+                       BoolProperty,
+                       EnumProperty,
+                       IntProperty,
+                       CollectionProperty)
+from bpy.types import Operator
+from bpy_extras.io_utils import ImportHelper, ExportHelper
+
+
+#
+#  Functions / Classes.
+#
+
+extension_panel_unregister_functors = []
+
+class ExportGLTF2_Base:
+    # TODO: refactor to avoid boilerplate
+
+    def __init__(self):
+        from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension
+        self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists()
+
+    bl_options = {'PRESET'}
+
+    export_format: EnumProperty(
+        name='Format',
+        items=(('GLB', 'glTF Binary (.glb)',
+                'Exports a single file, with all data packed in binary form. '
+                'Most efficient and portable, but more difficult to edit later'),
+               ('GLTF_EMBEDDED', 'glTF Embedded (.gltf)',
+                'Exports a single file, with all data packed in JSON. '
+                'Less efficient than binary, but easier to edit later'),
+               ('GLTF_SEPARATE', 'glTF Separate (.gltf + .bin + textures)',
+                'Exports multiple files, with separate JSON, binary and texture data. '
+                'Easiest to edit later')),
+        description=(
+            'Output format and embedding options. Binary is most efficient, '
+            'but JSON (embedded or separate) may be easier to edit later'
+        ),
+        default='GLB'
+    )
+
+    ui_tab: EnumProperty(
+        items=(('GENERAL', "General", "General settings"),
+               ('MESHES', "Meshes", "Mesh settings"),
+               ('OBJECTS', "Objects", "Object settings"),
+               ('ANIMATION', "Animation", "Animation settings")),
+        name="ui_tab",
+        description="Export setting categories",
+    )
+
+    export_copyright: StringProperty(
+        name='Copyright',
+        description='Legal rights and conditions for the model',
+        default=''
+    )
+
+    export_image_format: EnumProperty(
+        name='Images',
+        items=(('AUTO', 'Automatic',
+                'Save PNGs as PNGs and JPEGs as JPEGs.\n'
+                'If neither one, use PNG'),
+                ('JPEG', 'JPEG Format (.jpg)',
+                'Save images as JPEGs. (Images that need alpha are saved as PNGs though.)\n'
+                'Be aware of a possible loss in quality'),
+               ),
+        description=(
+            'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
+            'applications due to the smaller file size'
+        ),
+        default='AUTO'
+    )
+
+    export_texture_dir: StringProperty(
+        name='Textures',
+        description='Folder to place texture files in. Relative to the .gltf file',
+        default='',
+    )
+
+    export_texcoords: BoolProperty(
+        name='UVs',
+        description='Export UVs (texture coordinates) with meshes',
+        default=True
+    )
+
+    export_normals: BoolProperty(
+        name='Normals',
+        description='Export vertex normals with meshes',
+        default=True
+    )
+
+    export_draco_mesh_compression_enable: BoolProperty(
+        name='Draco mesh compression',
+        description='Compress mesh using Draco',
+        default=False
+    )
+
+    export_draco_mesh_compression_level: IntProperty(
+        name='Compression level',
+        description='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
+        default=6,
+        min=0,
+        max=6
+    )
+
+    export_draco_position_quantization: IntProperty(
+        name='Position quantization bits',
+        description='Quantization bits for position values (0 = no quantization)',
+        default=14,
+        min=0,
+        max=30
+    )
+
+    export_draco_normal_quantization: IntProperty(
+        name='Normal quantization bits',
+        description='Quantization bits for normal values (0 = no quantization)',
+        default=10,
+        min=0,
+        max=30
+    )
+
+    export_draco_texcoord_quantization: IntProperty(
+        name='Texcoord quantization bits',
+        description='Quantization bits for texture coordinate values (0 = no quantization)',
+        default=12,
+        min=0,
+        max=30
+    )
+
+    export_draco_generic_quantization: IntProperty(
+        name='Generic quantization bits',
+        description='Quantization bits for generic coordinate values like weights or joints (0 = no quantization)',
+        default=12,
+        min=0,
+        max=30
+    )
+
+    export_tangents: BoolProperty(
+        name='Tangents',
+        description='Export vertex tangents with meshes',
+        default=False
+    )
+
+    export_materials: BoolProperty(
+        name='Materials',
+        description='Export materials',
+        default=True
+    )
+
+    export_colors: BoolProperty(
+        name='Vertex Colors',
+        description='Export vertex colors with meshes',
+        default=True
+    )
+
+    export_cameras: BoolProperty(
+        name='Cameras',
+        description='Export cameras',
+        default=False
+    )
+
+    # keep it for compatibility (for now)
+    export_selected: BoolProperty(
+        name='Selected Objects',
+        description='Export selected objects only',
+        default=False
+    )
+
+    use_selection: BoolProperty(
+        name='Selected Objects',
+        description='Export selected objects only',
+        default=False
+    )
+
+    export_extras: BoolProperty(
+        name='Custom Properties',
+        description='Export custom properties as glTF extras',
+        default=False
+    )
+
+    export_yup: BoolProperty(
+        name='+Y Up',
+        description='Export using glTF convention, +Y up',
+        default=True
+    )
+
+    export_apply: BoolProperty(
+        name='Apply Modifiers',
+        description='Apply modifiers (excluding Armatures) to mesh objects -'
+                    'WARNING: prevents exporting shape keys',
+        default=False
+    )
+
+    export_animations: BoolProperty(
+        name='Animations',
+        description='Exports active actions and NLA tracks as glTF animations',
+        default=True
+    )
+
+    export_frame_range: BoolProperty(
+        name='Limit to Playback Range',
+        description='Clips animations to selected playback range',
+        default=True
+    )
+
+    export_frame_step: IntProperty(
+        name='Sampling Rate',
+        description='How often to evaluate animated values (in frames)',
+        default=1,
+        min=1,
+        max=120
+    )
+
+    export_force_sampling: BoolProperty(
+        name='Always Sample Animations',
+        description='Apply sampling to all animations',
+        default=True
+    )
+
+    export_nla_strips: BoolProperty(
+        name='Group by NLA Track',
+        description=(
+            "When on, multiple actions become part of the same glTF animation if\n"
+            "they're pushed onto NLA tracks with the same name.\n"
+            "When off, all the currently assigned actions become one glTF animation"
+        ),
+        default=True
+    )
+
+    export_def_bones: BoolProperty(
+        name='Export Deformation Bones Only',
+        description='Export Deformation bones only (and needed bones for hierarchy)',
+        default=False
+    )
+
+    export_current_frame: BoolProperty(
+        name='Use Current Frame',
+        description='Export the scene in the current animation frame',
+        default=False
+    )
+
+    export_skins: BoolProperty(
+        name='Skinning',
+        description='Export skinning (armature) data',
+        default=True
+    )
+
+    export_all_influences: BoolProperty(
+        name='Include All Bone Influences',
+        description='Allow >4 joint vertex influences. Models may appear incorrectly in many viewers',
+        default=False
+    )
+
+    export_morph: BoolProperty(
+        name='Shape Keys',
+        description='Export shape keys (morph targets)',
+        default=True
+    )
+
+    export_morph_normal: BoolProperty(
+        name='Shape Key Normals',
+        description='Export vertex normals with shape keys (morph targets)',
+        default=True
+    )
+
+    export_morph_tangent: BoolProperty(
+        name='Shape Key Tangents',
+        description='Export vertex tangents with shape keys (morph targets)',
+        default=False
+    )
+
+    export_lights: BoolProperty(
+        name='Punctual Lights',
+        description='Export directional, point, and spot lights. '
+                    'Uses "KHR_lights_punctual" glTF extension',
+        default=False
+    )
+
+    export_displacement: BoolProperty(
+        name='Displacement Textures (EXPERIMENTAL)',
+        description='EXPERIMENTAL: Export displacement textures. '
+                    'Uses incomplete "KHR_materials_displacement" glTF extension',
+        default=False
+    )
+
+    will_save_settings: BoolProperty(
+        name='Remember Export Settings',
+        description='Store glTF export settings in the Blender project',
+        default=False)
+
+    # Custom scene property for saving settings
+    scene_key = "glTF2ExportSettings"
+
+    #
+
+    def invoke(self, context, event):
+        settings = context.scene.get(self.scene_key)
+        self.will_save_settings = False
+        self.has_active_extenions = False
+        if settings:
+            try:
+                for (k, v) in settings.items():
+                    if k == "export_selected": # Back compatibility for export_selected --> use_selection
+                        setattr(self, "use_selection", v)
+                        del settings[k]
+                        settings["use_selection"] = v
+                        print("export_selected is now renamed use_selection, and will be deleted in a few release")
+                    else:
+                        setattr(self, k, v)
+                self.will_save_settings = True
+
+            except (AttributeError, TypeError):
+                self.report({"ERROR"}, "Loading export settings failed. Removed corrupted settings")
+                del context.scene[self.scene_key]
+
+        import sys
+        preferences = bpy.context.preferences
+        for addon_name in preferences.addons.keys():
+            try:
+                if hasattr(sys.modules[addon_name], 'glTF2ExportUserExtension') or hasattr(sys.modules[addon_name], 'glTF2ExportUserExtensions'):
+                    extension_panel_unregister_functors.append(sys.modules[addon_name].register_panel())
+                    self.has_active_extenions = True
+            except Exception:
+                pass
+
+        return ExportHelper.invoke(self, context, event)
+
+    def save_settings(self, context):
+        # find all export_ props
+        all_props = self.properties
+        export_props = {x: getattr(self, x) for x in dir(all_props)
+                        if x.startswith("export_") and all_props.get(x) is not None}
+
+        context.scene[self.scene_key] = export_props
+
+    def execute(self, context):
+        import os
+        import datetime
+        from .blender.exp import gltf2_blender_export
+
+        if self.will_save_settings:
+            self.save_settings(context)
+
+        if self.export_format == 'GLB':
+            self.filename_ext = '.glb'
+        else:
+            self.filename_ext = '.gltf'
+
+        # All custom export settings are stored in this container.
+        export_settings = {}
+
+        export_settings['timestamp'] = datetime.datetime.now()
+
+        export_settings['gltf_filepath'] = bpy.path.ensure_ext(self.filepath, self.filename_ext)
+        export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
+        export_settings['gltf_texturedirectory'] = os.path.join(
+            export_settings['gltf_filedirectory'],
+            self.export_texture_dir,
+        )
+
+        export_settings['gltf_format'] = self.export_format
+        export_settings['gltf_image_format'] = self.export_image_format
+        export_settings['gltf_copyright'] = self.export_copyright
+        export_settings['gltf_texcoords'] = self.export_texcoords
+        export_settings['gltf_normals'] = self.export_normals
+        export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
+
+        if self.is_draco_available:
+            export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
+            export_settings['gltf_draco_mesh_compression_level'] = self.export_draco_mesh_compression_level
+            export_settings['gltf_draco_position_quantization'] = self.export_draco_position_quantization
+            export_settings['gltf_draco_normal_quantization'] = self.export_draco_normal_quantization
+            export_settings['gltf_draco_texcoord_quantization'] = self.export_draco_texcoord_quantization
+            export_settings['gltf_draco_generic_quantization'] = self.export_draco_generic_quantization
+        else:
+            export_settings['gltf_draco_mesh_compression'] = False
+
+        export_settings['gltf_materials'] = self.export_materials
+        export_settings['gltf_colors'] = self.export_colors
+        export_settings['gltf_cameras'] = self.export_cameras
+
+        # compatibility after renaming export_selected to use_selection
+        if self.export_selected is True:
+            self.report({"WARNING"}, "export_selected is now renamed use_selection, and will be deleted in a few release")
+            export_settings['gltf_selected'] = self.export_selected
+        else:
+            export_settings['gltf_selected'] = self.use_selection
+
+        # export_settings['gltf_selected'] = self.use_selection This can be uncomment when removing compatibility of export_selected
+        export_settings['gltf_layers'] = True  # self.export_layers
+        export_settings['gltf_extras'] = self.export_extras
+        export_settings['gltf_yup'] = self.export_yup
+        export_settings['gltf_apply'] = self.export_apply
+        export_settings['gltf_current_frame'] = self.export_current_frame
+        export_settings['gltf_animations'] = self.export_animations
+        if self.export_animations:
+            export_settings['gltf_frame_range'] = self.export_frame_range
+            export_settings['gltf_force_sampling'] = self.export_force_sampling
+            if self.export_force_sampling:
+                export_settings['gltf_def_bones'] = self.export_def_bones
+            else:
+                export_settings['gltf_def_bones'] = False
+            export_settings['gltf_nla_strips'] = self.export_nla_strips
+        else:
+            export_settings['gltf_frame_range'] = False
+            export_settings['gltf_move_keyframes'] = False
+            export_settings['gltf_force_sampling'] = False
+            export_settings['gltf_def_bones'] = False
+        export_settings['gltf_skins'] = self.export_skins
+        if self.export_skins:
+            export_settings['gltf_all_vertex_influences'] = self.export_all_influences
+        else:
+            export_settings['gltf_all_vertex_influences'] = False
+        export_settings['gltf_frame_step'] = self.export_frame_step
+        export_settings['gltf_morph'] = self.export_morph
+        if self.export_morph:
+            export_settings['gltf_morph_normal'] = self.export_morph_normal
+        else:
+            export_settings['gltf_morph_normal'] = False
+        if self.export_morph and self.export_morph_normal:
+            export_settings['gltf_morph_tangent'] = self.export_morph_tangent
+        else:
+            export_settings['gltf_morph_tangent'] = False
+
+        export_settings['gltf_lights'] = self.export_lights
+        export_settings['gltf_displacement'] = self.export_displacement
+
+        export_settings['gltf_binary'] = bytearray()
+        export_settings['gltf_binaryfilename'] = os.path.splitext(os.path.basename(
+            bpy.path.ensure_ext(self.filepath,self.filename_ext)))[0] + '.bin'
+
+        user_extensions = []
+
+        import sys
+        preferences = bpy.context.preferences
+        for addon_name in preferences.addons.keys():
+            try:
+                module = sys.modules[addon_name]
+            except Exception:
+                continue
+            if hasattr(module, 'glTF2ExportUserExtension'):
+                extension_ctor = module.glTF2ExportUserExtension
+                user_extensions.append(extension_ctor())
+            if hasattr(module, 'glTF2ExportUserExtensions'):
+                extension_ctors = module.glTF2ExportUserExtensions
+                for extension_ctor in extension_ctors:
+                    user_extensions.append(extension_ctor())
+        export_settings['gltf_user_extensions'] = user_extensions
+
+        return gltf2_blender_export.save(context, export_settings)
+
+    def draw(self, context):
+        pass # Is needed to get panels available
+
+
+class GLTF_PT_export_main(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = ""
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'HIDE_HEADER'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_format')
+        if operator.export_format == 'GLTF_SEPARATE':
+            layout.prop(operator, 'export_texture_dir', icon='FILE_FOLDER')
+        layout.prop(operator, 'export_copyright')
+        layout.prop(operator, 'will_save_settings')
+
+
+class GLTF_PT_export_include(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Include"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        col = layout.column(heading = "Limit to", align = True)
+        col.prop(operator, 'use_selection')
+
+        col = layout.column(heading = "Data", align = True)
+        col.prop(operator, 'export_extras')
+        col.prop(operator, 'export_cameras')
+        col.prop(operator, 'export_lights')
+
+
+class GLTF_PT_export_transform(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Transform"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_yup')
+
+
+class GLTF_PT_export_geometry(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Geometry"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_apply')
+        layout.prop(operator, 'export_texcoords')
+        layout.prop(operator, 'export_normals')
+        col = layout.column()
+        col.active = operator.export_normals
+        col.prop(operator, 'export_tangents')
+        layout.prop(operator, 'export_colors')
+        layout.prop(operator, 'export_materials')
+        col = layout.column()
+        col.active = operator.export_materials
+        col.prop(operator, 'export_image_format')
+
+
+class GLTF_PT_export_geometry_compression(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Compression"
+    bl_parent_id = "GLTF_PT_export_geometry"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def __init__(self):
+        from io_scene_gltf2.io.exp import gltf2_io_draco_compression_extension
+        self.is_draco_available = gltf2_io_draco_compression_extension.dll_exists(quiet=True)
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        if operator.is_draco_available:
+            return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_draco_mesh_compression_enable", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_draco_mesh_compression_enable
+        layout.prop(operator, 'export_draco_mesh_compression_level')
+
+        col = layout.column(align=True)
+        col.prop(operator, 'export_draco_position_quantization', text="Quantize Position")
+        col.prop(operator, 'export_draco_normal_quantization', text="Normal")
+        col.prop(operator, 'export_draco_texcoord_quantization', text="Tex Coords")
+        col.prop(operator, 'export_draco_generic_quantization', text="Generic")
+
+
+class GLTF_PT_export_animation(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.prop(operator, 'export_current_frame')
+
+
+class GLTF_PT_export_animation_export(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Animation"
+    bl_parent_id = "GLTF_PT_export_animation"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_animations", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_animations
+
+        layout.prop(operator, 'export_frame_range')
+        layout.prop(operator, 'export_frame_step')
+        layout.prop(operator, 'export_force_sampling')
+        layout.prop(operator, 'export_nla_strips')
+
+        row = layout.row()
+        row.active = operator.export_force_sampling
+        row.prop(operator, 'export_def_bones')
+
+
+class GLTF_PT_export_animation_shapekeys(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Shape Keys"
+    bl_parent_id = "GLTF_PT_export_animation"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_morph", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_morph
+
+        layout.prop(operator, 'export_morph_normal')
+        col = layout.column()
+        col.active = operator.export_morph_normal
+        col.prop(operator, 'export_morph_tangent')
+
+
+class GLTF_PT_export_animation_skinning(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Skinning"
+    bl_parent_id = "GLTF_PT_export_animation"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
+
+    def draw_header(self, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+        self.layout.prop(operator, "export_skins", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        layout.active = operator.export_skins
+        layout.prop(operator, 'export_all_influences')
+
+class GLTF_PT_export_user_extensions(bpy.types.Panel):
+    bl_space_type = 'FILE_BROWSER'
+    bl_region_type = 'TOOL_PROPS'
+    bl_label = "Extensions"
+    bl_parent_id = "FILE_PT_operator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        sfile = context.space_data
+        operator = sfile.active_operator
+
+        return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_extenions
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+
+class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
+    """Export scene as glTF 2.0 file"""
+    bl_idname = 'export_scene.gltf'
+    bl_label = 'Export glTF 2.0'
+
+    filename_ext = ''
+
+    filter_glob: StringProperty(default='*.glb;*.gltf', options={'HIDDEN'})
+
+
+def menu_func_export(self, context):
+    self.layout.operator(ExportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
+
+
+class ImportGLTF2(Operator, ImportHelper):
+    """Load a glTF 2.0 file"""
+    bl_idname = 'import_scene.gltf'
+    bl_label = 'Import glTF 2.0'
+
+    filter_glob: StringProperty(default="*.glb;*.gltf", options={'HIDDEN'})
+
+    files: CollectionProperty(
+        name="File Path",
+        type=bpy.types.OperatorFileListElement,
+    )
+
+    loglevel: IntProperty(
+        name='Log Level',
+        description="Log Level")
+
+    import_pack_images: BoolProperty(
+        name='Pack Images',
+        description='Pack all images into .blend file',
+        default=True
+    )
+
+    import_shading: EnumProperty(
+        name="Shading",
+        items=(("NORMALS", "Use Normal Data", ""),
+               ("FLAT", "Flat Shading", ""),
+               ("SMOOTH", "Smooth Shading", "")),
+        description="How normals are computed during import",
+        default="NORMALS")
+
+    bone_heuristic: EnumProperty(
+        name="Bone Dir",
+        items=(
+            ("BLENDER", "Blender (best for re-importing)",
+                "Good for re-importing glTFs exported from Blender.\n"
+                "Bone tips are placed on their local +Y axis (in glTF space)"),
+            ("TEMPERANCE", "Temperance (average)",
+                "Decent all-around strategy.\n"
+                "A bone with one child has its tip placed on the local axis\n"
+                "closest to its child"),
+            ("FORTUNE", "Fortune (may look better, less accurate)",
+                "Might look better than Temperance, but also might have errors.\n"
+                "A bone with one child has its tip placed at its child's root.\n"
+                "Non-uniform scalings may get messed up though, so beware"),
+        ),
+        description="Heuristic for placing bones. Tries to make bones pretty",
+        default="TEMPERANCE",
+    )
+
+    guess_original_bind_pose: BoolProperty(
+        name='Guess Original Bind Pose',
+        description=(
+            'Try to guess the original bind pose for skinned meshes from '
+            'the inverse bind matrices.\n'
+            'When off, use default/rest pose as bind pose'
+        ),
+        default=True,
+    )
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.use_property_split = True
+        layout.use_property_decorate = False  # No animation.
+
+        layout.prop(self, 'import_pack_images')
+        layout.prop(self, 'import_shading')
+        layout.prop(self, 'guess_original_bind_pose')
+        layout.prop(self, 'bone_heuristic')
+
+    def execute(self, context):
+        return self.import_gltf2(context)
+
+    def import_gltf2(self, context):
+        import os
+
+        self.set_debug_log()
+        import_settings = self.as_keywords()
+
+        if self.files:
+            # Multiple file import
+            ret = {'CANCELLED'}
+            dirname = os.path.dirname(self.filepath)
+            for file in self.files:
+                path = os.path.join(dirname, file.name)
+                if self.unit_import(path, import_settings) == {'FINISHED'}:
+                    ret = {'FINISHED'}
+            return ret
+        else:
+            # Single file import
+            return self.unit_import(self.filepath, import_settings)
+
+    def unit_import(self, filename, import_settings):
+        import time
+        from .io.imp.gltf2_io_gltf import glTFImporter
+        from .blender.imp.gltf2_blender_gltf import BlenderGlTF
+
+        self.gltf_importer = glTFImporter(filename, import_settings)
+        success, txt = self.gltf_importer.read()
+        if not success:
+            self.report({'ERROR'}, txt)
+            return {'CANCELLED'}
+        success, txt = self.gltf_importer.checks()
+        if not success:
+            self.report({'ERROR'}, txt)
+            return {'CANCELLED'}
+        print("Data are loaded, start creating Blender stuff")
+        start_time = time.time()
+        BlenderGlTF.create(self.gltf_importer)
+        elapsed_s = "{:.2f}s".format(time.time() - start_time)
+        print("glTF import finished in " + elapsed_s)
+        self.gltf_importer.log.removeHandler(self.gltf_importer.log_handler)
+
+        return {'FINISHED'}
+
+    def set_debug_log(self):
+        import logging
+        if bpy.app.debug_value == 0:
+            self.loglevel = logging.CRITICAL
+        elif bpy.app.debug_value == 1:
+            self.loglevel = logging.ERROR
+        elif bpy.app.debug_value == 2:
+            self.loglevel = logging.WARNING
+        elif bpy.app.debug_value == 3:
+            self.loglevel = logging.INFO
+        else:
+            self.loglevel = logging.NOTSET
+
+
+def menu_func_import(self, context):
+    self.layout.operator(ImportGLTF2.bl_idname, text='glTF 2.0 (.glb/.gltf)')
+
+
+classes = (
+    ExportGLTF2,
+    GLTF_PT_export_main,
+    GLTF_PT_export_include,
+    GLTF_PT_export_transform,
+    GLTF_PT_export_geometry,
+    GLTF_PT_export_geometry_compression,
+    GLTF_PT_export_animation,
+    GLTF_PT_export_animation_export,
+    GLTF_PT_export_animation_shapekeys,
+    GLTF_PT_export_animation_skinning,
+    GLTF_PT_export_user_extensions,
+    ImportGLTF2
+)
+
+
+def register():
+    for c in classes:
+        bpy.utils.register_class(c)
+    # bpy.utils.register_module(__name__)
+
+    # add to the export / import menu
+    bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
+    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
+
+
+def unregister():
+    for c in classes:
+        bpy.utils.unregister_class(c)
+    for f in extension_panel_unregister_functors:
+        f()
+    extension_panel_unregister_functors.clear()
+
+    # bpy.utils.unregister_module(__name__)
+
+    # remove from the export / import menu
+    bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
+    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
-- 
GitLab